1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Shared code used by the name-service-switch frontends (e.g. getpwnam_r()) 31 */ 32 33 #pragma weak nss_delete = _nss_delete 34 #pragma weak nss_endent = _nss_endent 35 #pragma weak nss_getent = _nss_getent 36 #pragma weak nss_search = _nss_search 37 #pragma weak nss_setent = _nss_setent 38 39 #include "synonyms.h" 40 #include <mtlib.h> 41 #include <dlfcn.h> 42 #include <atomic.h> 43 44 #define __NSS_PRIVATE_INTERFACE 45 #include "nsswitch_priv.h" 46 #undef __NSS_PRIVATE_INTERFACE 47 48 #include <nss_common.h> 49 #include <nss_dbdefs.h> 50 #include <unistd.h> 51 #include <stdlib.h> 52 #include <stdio.h> 53 #include <string.h> 54 #include <thread.h> 55 #include <synch.h> 56 #include <pthread.h> 57 #include <sys/types.h> 58 #include <sys/mman.h> 59 #include <errno.h> 60 #include "libc.h" 61 #include "tsd.h" 62 63 #include <getxby_door.h> 64 65 /* 66 * policy component function interposing definitions: 67 * nscd if so desired can interpose it's own switch functions over 68 * the internal unlocked counterparts. This will allow nscd to replace 69 * the switch policy state engine with one that uses it's internal 70 * components. 71 * Only nscd can change this through it's use of nss_config. 72 * The golden rule is: ptr == NULL checking is used in the switch to 73 * see if a function was interposed. But nscd is responsible for seeing 74 * that mutex locking to change the values are observed when the data is 75 * changed. Especially if it happens > once. The switch does not lock 76 * the pointer with mutexs. 77 */ 78 79 typedef struct { 80 void *p; 81 #if 0 82 void (*nss_delete_fp)(nss_db_root_t *rootp); 83 nss_status_t (*nss_search_fp)(nss_db_root_t *rootp, 84 nss_db_initf_t initf, int search_fnum, 85 void *search_args); 86 void (*nss_setent_u_fp)(nss_db_root_t *, 87 nss_db_initf_t, nss_getent_t *); 88 nss_status_t (*nss_getent_u_fp)(nss_db_root_t *, 89 nss_db_initf_t, nss_getent_t *, void *); 90 void (*nss_endent_u_fp)(nss_db_root_t *, 91 nss_db_initf_t, nss_getent_t *); 92 void (*end_iter_u_fp)(nss_db_root_t *rootp, 93 struct nss_getent_context *contextp); 94 #endif 95 } nss_policyf_t; 96 97 static mutex_t nss_policyf_lock = DEFAULTMUTEX; 98 static nss_policyf_t nss_policyf_ptrs = 99 { (void *)NULL }; 100 101 /* 102 * nsswitch db_root state machine definitions: 103 * The golden rule is: if you hold a pointer to an nss_db_state struct and 104 * you don't hold the lock, you'd better have incremented the refcount 105 * while you held the lock; otherwise, it may vanish or change 106 * significantly when you least expect it. 107 * 108 * The pointer in nss_db_root_t is one such, so the reference count >= 1. 109 * Ditto the pointer in struct nss_getent_context. 110 */ 111 112 /* 113 * State for one nsswitch database (e.g. "passwd", "hosts") 114 */ 115 struct nss_db_state { 116 nss_db_root_t orphan_root; /* XXX explain */ 117 unsigned refcount; /* One for the pointer in */ 118 /* nss_db_root_t, plus one */ 119 /* for each active thread. */ 120 nss_db_params_t p; 121 struct __nsw_switchconfig_v1 *config; 122 int max_src; /* is == config->num_lookups */ 123 struct nss_src_state *src; /* Pointer to array[max_src] */ 124 }; 125 126 /* 127 * State for one of the sources (e.g. "nis", "compat") for a database 128 */ 129 struct nss_src_state { 130 struct __nsw_lookup_v1 *lkp; 131 int n_active; 132 int n_dormant; 133 int n_waiting; /* ... on wanna_be */ 134 cond_t wanna_be; 135 union { 136 nss_backend_t *single; /* Efficiency hack for common case */ 137 /* when limit_dead_backends == 1 */ 138 nss_backend_t **multi; /* array[limit_dead_backends] of */ 139 } dormant; /* pointers to dormant backends */ 140 nss_backend_constr_t be_constr; 141 nss_backend_finder_t *finder; 142 void *finder_priv; 143 }; 144 145 static struct nss_db_state *_nss_db_state_constr(nss_db_initf_t); 146 void _nss_db_state_destr(struct nss_db_state *); 147 148 /* ==== null definitions if !MTSAFE? Ditto lock field in nss_db_root_t */ 149 150 #define NSS_ROOTLOCK(r, sp) (cancel_safe_mutex_lock(&(r)->lock), \ 151 *(sp) = (r)->s) 152 153 #define NSS_UNLOCK(r) (cancel_safe_mutex_unlock(&(r)->lock)) 154 155 #define NSS_CHECKROOT(rp, s) ((s) != (*(rp))->s && \ 156 (cancel_safe_mutex_unlock(&(*(rp))->lock), \ 157 cancel_safe_mutex_lock(&(s)->orphan_root.lock), \ 158 *(rp) = &(s)->orphan_root)) 159 160 #define NSS_RELOCK(rp, s) (cancel_safe_mutex_lock(&(*(rp))->lock), \ 161 NSS_CHECKROOT(rp, s)) 162 163 #define NSS_STATE_REF_u(s) (++(s)->refcount) 164 165 #define NSS_UNREF_UNLOCK(r, s) (--(s)->refcount != 0 \ 166 ? ((void)NSS_UNLOCK(r)) \ 167 : ((void)NSS_UNLOCK(r), (void)_nss_db_state_destr(s))) 168 169 #define NSS_LOCK_CHECK(r, f, sp) (NSS_ROOTLOCK((r), (sp)), \ 170 *(sp) == 0 && \ 171 (r->s = *(sp) = _nss_db_state_constr(f))) 172 /* === In the future, NSS_LOCK_CHECK() may also have to check that */ 173 /* === the config info hasn't changed (by comparing version numbers) */ 174 175 176 /* 177 * NSS_OPTIONS/NIS_OPTIONS environment varibles data definitions: 178 * This remains for backwards compatibility. But generally nscd will 179 * decide if/how this gets used. 180 */ 181 static int checked_env = 0; /* protected by "rootlock" */ 182 183 /* allowing __nss_debug_file to be set could be a security hole. */ 184 FILE *__nss_debug_file = stdout; 185 int __nss_debug_eng_loop; 186 187 /* NIS_OPTIONS infrastructure (from linbsl/nis/cache/cache_api.cc) */ 188 /* allowing __nis_debug_file to be set could be a security hole. */ 189 FILE *__nis_debug_file = stdout; 190 int __nis_debug_bind; 191 int __nis_debug_rpc; 192 int __nis_debug_calls; 193 char *__nis_prefsrv; 194 char *__nis_preftype; 195 char *__nis_server; /* if set, use only this server for binding */ 196 197 #define OPT_INT 1 198 #define OPT_STRING 2 199 #ifdef DEBUG 200 #define OPT_FILE 3 201 #endif 202 203 struct option { 204 char *name; 205 int type; 206 void *address; 207 }; 208 209 static struct option nss_options[] = { 210 #ifdef DEBUG 211 /* allowing __nss_debug_file to be set could be a security hole. */ 212 { "debug_file", OPT_FILE, &__nss_debug_file }, 213 #endif 214 { "debug_eng_loop", OPT_INT, &__nss_debug_eng_loop }, 215 { 0, 0, 0 }, 216 }; 217 218 static struct option nis_options[] = { 219 #ifdef DEBUG 220 /* allowing __nis_debug_file to be set could be a security hole. */ 221 { "debug_file", OPT_FILE, &__nis_debug_file }, 222 #endif 223 { "debug_bind", OPT_INT, &__nis_debug_bind }, 224 { "debug_rpc", OPT_INT, &__nis_debug_rpc }, 225 { "debug_calls", OPT_INT, &__nis_debug_calls }, 226 { "server", OPT_STRING, &__nis_server }, 227 { "pref_srvr", OPT_STRING, &__nis_prefsrv }, 228 { "pref_type", OPT_STRING, &__nis_preftype }, 229 { 0, 0, 0 }, 230 }; 231 232 /* 233 * switch configuration parameter "database" definitions: 234 * The switch maintains a simmple read/write parameter database 235 * that nscd and the switch components can use to communicate 236 * nscd data to other components for configuration or out of band 237 * [IE no in the context of a getXbyY or putXbyY operation] data. 238 * The data passed are pointers to a lock data buffer and a length. 239 * Use of this is treated as SunwPrivate between nscd and the switch 240 * unless other wise stated. 241 */ 242 243 typedef struct nss_cfgparam { 244 char *name; 245 mutex_t *lock; 246 void *buffer; 247 size_t length; 248 } nss_cfgparam_t; 249 250 typedef struct nss_cfglist { 251 char *name; 252 nss_cfgparam_t *list; 253 int count; 254 int max; 255 } nss_cfglist_t; 256 257 #define NSS_CFG_INCR 16 258 259 static nss_cfglist_t *nss_cfg = NULL; 260 static int nss_cfgcount = 0; 261 static int nss_cfgmax = 0; 262 static mutex_t nss_cfglock = DEFAULTMUTEX; 263 264 static int nss_cfg_policy_init(); 265 266 /* 267 * A config parameters are in the form component:parameter 268 * as in: nss:parameter - switch (internal FE/policy/BE) parameter 269 * nscd:param - nscd application parameter 270 * ldap:param - nss_ldap BE parameter 271 * passwd:param - get/put passwd FE parameter 272 */ 273 274 #define NSS_CONFIG_BRK ':' 275 276 /* 277 * The policy components initial parameter list 278 */ 279 static nss_config_t nss_policy_params[] = { 280 { "nss:policyfunc", NSS_CONFIG_ADD, &nss_policyf_lock, 281 (void *)&nss_policyf_ptrs, (size_t)sizeof (nss_policyf_t) }, 282 { NULL, NSS_CONFIG_ADD, (mutex_t *)NULL, (void *)NULL, (size_t)0 }, 283 }; 284 285 /* 286 * NSS parameter configuration routines 287 */ 288 289 /* compare config name (component:parameter) to a component name */ 290 static int 291 nss_cfgcn_cmp(const char *cfgname, const char *compname) 292 { 293 char *c; 294 size_t len, len2; 295 296 /* this code assumes valid pointers */ 297 if ((c = strchr(cfgname, NSS_CONFIG_BRK)) == NULL) 298 return (-1); 299 len = (size_t)(c - cfgname); 300 len2 = strlen(compname); 301 if (len2 != len) 302 return (-1); 303 return (strncmp(cfgname, compname, len)); 304 } 305 306 /* init configuration arena */ 307 static int 308 nss_cfg_init() 309 { 310 nss_cfglist_t *cfg; 311 int i; 312 313 /* First time caller? */ 314 if (nss_cfg != NULL) { 315 membar_consumer(); 316 return (0); 317 } 318 319 /* Initialize internal tables */ 320 lmutex_lock(&nss_cfglock); 321 if (nss_cfg != NULL) { 322 lmutex_unlock(&nss_cfglock); 323 membar_consumer(); 324 return (0); 325 } 326 cfg = libc_malloc(NSS_CFG_INCR * sizeof (nss_cfglist_t)); 327 if (cfg == NULL) { 328 errno = ENOMEM; 329 lmutex_unlock(&nss_cfglock); 330 return (-1); 331 } 332 for (i = 0; i < NSS_CFG_INCR; i++) { 333 cfg[i].list = libc_malloc( 334 NSS_CFG_INCR * sizeof (nss_cfgparam_t)); 335 if (cfg[i].list == NULL) { 336 while (--i >= 0) 337 libc_free(cfg[i].list); 338 libc_free(cfg); 339 errno = ENOMEM; 340 lmutex_unlock(&nss_cfglock); 341 return (-1); 342 } 343 cfg[i].max = NSS_CFG_INCR; 344 } 345 nss_cfgmax = NSS_CFG_INCR; 346 membar_producer(); 347 nss_cfg = cfg; 348 lmutex_unlock(&nss_cfglock); 349 350 /* Initialize Policy Engine values */ 351 if (nss_cfg_policy_init() < 0) { 352 return (-1); 353 } 354 return (0); 355 } 356 357 /* find the name'd component list - create it if non-existent */ 358 static nss_cfglist_t * 359 nss_cfgcomp_get(char *name, int add) 360 { 361 nss_cfglist_t *next; 362 char *c; 363 int i, len; 364 size_t nsize; 365 366 /* Make sure system is init'd */ 367 if (nss_cfg_init() < 0) 368 return ((nss_cfglist_t *)NULL); 369 370 /* and check component:name validity */ 371 if (name == NULL || (c = strchr(name, NSS_CONFIG_BRK)) == NULL) 372 return ((nss_cfglist_t *)NULL); 373 374 lmutex_lock(&nss_cfglock); 375 next = nss_cfg; 376 for (i = 0; i < nss_cfgcount; i++) { 377 if (next->name && nss_cfgcn_cmp(name, next->name) == 0) { 378 lmutex_unlock(&nss_cfglock); 379 return (next); 380 } 381 next++; 382 } 383 if (!add) { 384 lmutex_unlock(&nss_cfglock); 385 return (NULL); 386 } 387 388 /* not found, create a fresh one */ 389 if (nss_cfgcount >= nss_cfgmax) { 390 /* realloc first */ 391 nsize = (nss_cfgmax + NSS_CFG_INCR) * sizeof (nss_cfgparam_t); 392 next = (nss_cfglist_t *)libc_realloc(nss_cfg, nsize); 393 if (next == NULL) { 394 errno = ENOMEM; 395 lmutex_unlock(&nss_cfglock); 396 return ((nss_cfglist_t *)NULL); 397 } 398 (void) memset((void *)(next + nss_cfgcount), '\0', 399 NSS_CFG_INCR * sizeof (nss_cfglist_t)); 400 nss_cfgmax += NSS_CFG_INCR; 401 nss_cfg = next; 402 } 403 next = nss_cfg + nss_cfgcount; 404 len = (size_t)(c - name) + 1; 405 if ((next->name = libc_malloc(len)) == NULL) { 406 errno = ENOMEM; 407 lmutex_unlock(&nss_cfglock); 408 return ((nss_cfglist_t *)NULL); 409 } 410 nss_cfgcount++; 411 (void) strlcpy(next->name, name, len); 412 lmutex_unlock(&nss_cfglock); 413 return (next); 414 } 415 416 /* find the name'd parameter - create it if non-existent */ 417 static nss_cfgparam_t * 418 nss_cfgparam_get(char *name, int add) 419 { 420 nss_cfglist_t *comp; 421 nss_cfgparam_t *next; 422 int count, i; 423 size_t nsize; 424 425 if ((comp = nss_cfgcomp_get(name, add)) == NULL) 426 return ((nss_cfgparam_t *)NULL); 427 lmutex_lock(&nss_cfglock); 428 count = comp->count; 429 next = comp->list; 430 for (i = 0; i < count; i++) { 431 if (next->name && strcmp(name, next->name) == 0) { 432 lmutex_unlock(&nss_cfglock); 433 return (next); 434 } 435 next++; 436 } 437 if (!add) { 438 lmutex_unlock(&nss_cfglock); 439 return (NULL); 440 } 441 442 /* not found, create a fresh one */ 443 if (count >= comp->max) { 444 /* realloc first */ 445 nsize = (comp->max + NSS_CFG_INCR) * sizeof (nss_cfgparam_t); 446 next = (nss_cfgparam_t *)libc_realloc(comp->list, nsize); 447 if (next == NULL) { 448 errno = ENOMEM; 449 lmutex_unlock(&nss_cfglock); 450 return ((nss_cfgparam_t *)NULL); 451 } 452 comp->max += NSS_CFG_INCR; 453 comp->list = next; 454 } 455 next = comp->list + comp->count; 456 if ((next->name = libc_strdup(name)) == NULL) { 457 errno = ENOMEM; 458 lmutex_unlock(&nss_cfglock); 459 return ((nss_cfgparam_t *)NULL); 460 } 461 comp->count++; 462 lmutex_unlock(&nss_cfglock); 463 return (next); 464 } 465 466 /* find the name'd parameter - delete it if it exists */ 467 static void 468 nss_cfg_del(nss_config_t *cfgp) 469 { 470 char *name; 471 nss_cfglist_t *comp; 472 nss_cfgparam_t *next, *cur; 473 int count, i, j; 474 475 /* exit if component name does not already exist */ 476 if ((name = cfgp->name) == NULL || 477 (comp = nss_cfgcomp_get(name, 0)) == NULL) 478 return; 479 480 /* find it */ 481 lmutex_lock(&nss_cfglock); 482 count = comp->count; 483 next = comp->list; 484 for (i = 0; i < count; i++) { 485 if (next->name && strcmp(name, next->name) == 0) { 486 break; /* found it... */ 487 } 488 next++; 489 } 490 if (i >= count) { 491 /* not found, already deleted */ 492 lmutex_unlock(&nss_cfglock); 493 return; 494 } 495 496 /* copy down the remaining parameters, and clean up */ 497 /* don't try to clean up component tables */ 498 cur = next; 499 next++; 500 for (j = i+1; j < count; j++) { 501 *cur = *next; 502 cur++; 503 next++; 504 } 505 /* erase the last one */ 506 if (cur->name) { 507 libc_free(cur->name); 508 cur->name = (char *)NULL; 509 } 510 cur->lock = (mutex_t *)NULL; 511 cur->buffer = (void *)NULL; 512 cur->length = 0; 513 comp->count--; 514 lmutex_unlock(&nss_cfglock); 515 } 516 517 static int 518 nss_cfg_get(nss_config_t *next) 519 { 520 nss_cfgparam_t *param; 521 522 errno = 0; 523 if ((param = nss_cfgparam_get(next->name, 0)) == NULL) 524 return (-1); 525 next->lock = param->lock; 526 next->buffer = param->buffer; 527 next->length = param->length; 528 return (0); 529 } 530 531 static int 532 nss_cfg_put(nss_config_t *next, int add) 533 { 534 nss_cfgparam_t *param; 535 536 errno = 0; 537 if ((param = nss_cfgparam_get(next->name, add)) == NULL) 538 return (-1); 539 param->lock = next->lock; 540 param->buffer = next->buffer; 541 param->length = next->length; 542 return (0); 543 } 544 545 /* 546 * Policy engine configurator - set and get interface 547 * argument is a NULL terminated list of set/get requests 548 * with input/result buffers and lengths. nss_cname is the 549 * specifier of a set or get operation and the property being 550 * managed. The intent is limited functions and expandability. 551 */ 552 553 nss_status_t 554 nss_config(nss_config_t **plist, int cnt) 555 { 556 nss_config_t *next; 557 int i; 558 559 /* interface is only available to nscd */ 560 if (_nsc_proc_is_cache() <= 0) { 561 return (NSS_UNAVAIL); 562 } 563 if (plist == NULL || cnt <= 0) 564 return (NSS_SUCCESS); 565 for (i = 0; i < cnt; i++) { 566 next = plist[i]; 567 if (next == NULL) 568 break; 569 if (next->name == NULL) { 570 errno = EFAULT; 571 return (NSS_ERROR); 572 } 573 switch (next->cop) { 574 case NSS_CONFIG_GET: 575 /* get current lock/buffer/length fields */ 576 if (nss_cfg_get(next) < 0) { 577 return (NSS_ERROR); 578 } 579 break; 580 case NSS_CONFIG_PUT: 581 /* set new lock/buffer/length fields */ 582 if (nss_cfg_put(next, 0) < 0) { 583 return (NSS_ERROR); 584 } 585 break; 586 case NSS_CONFIG_ADD: 587 /* add parameter & set new lock/buffer/length fields */ 588 if (nss_cfg_put(next, 1) < 0) { 589 return (NSS_ERROR); 590 } 591 break; 592 case NSS_CONFIG_DELETE: 593 /* delete parameter - should always work... */ 594 nss_cfg_del(next); 595 break; 596 case NSS_CONFIG_LIST: 597 break; 598 default: 599 continue; 600 } 601 } 602 return (NSS_SUCCESS); 603 } 604 605 /* 606 * This routine is called immediately after nss_cfg_init but prior to 607 * any commands from nscd being processed. The intent here is to 608 * initialize the nss:* parameters allowed by the policy component 609 * so that nscd can then proceed and modify them if so desired. 610 * 611 * We know we can only get here if we are nscd so we can skip the 612 * preliminaries. 613 */ 614 615 static int 616 nss_cfg_policy_init() 617 { 618 nss_config_t *next = &nss_policy_params[0]; 619 620 for (; next && next->name != NULL; next++) { 621 if (nss_cfg_put(next, 1) < 0) 622 return (-1); 623 } 624 return (0); 625 } 626 627 /* 628 * NSS_OPTION & NIS_OPTION environment variable functions 629 */ 630 631 static 632 void 633 set_option(struct option *opt, char *name, char *val) 634 { 635 int n; 636 char *p; 637 #ifdef DEBUG 638 FILE *fp; 639 #endif 640 641 for (; opt->name; opt++) { 642 if (strcmp(name, opt->name) == 0) { 643 switch (opt->type) { 644 case OPT_STRING: 645 p = libc_strdup(val); 646 *((char **)opt->address) = p; 647 break; 648 649 case OPT_INT: 650 if (strcmp(val, "") == 0) 651 n = 1; 652 else 653 n = atoi(val); 654 *((int *)opt->address) = n; 655 break; 656 #ifdef DEBUG 657 case OPT_FILE: 658 fp = fopen(val, "wF"); 659 *((FILE **)opt->address) = fp; 660 break; 661 #endif 662 } 663 break; 664 } 665 } 666 } 667 668 static 669 void 670 __parse_environment(struct option *opt, char *p) 671 { 672 char *base; 673 char optname[100]; 674 char optval[100]; 675 676 while (*p) { 677 while (isspace(*p)) 678 p++; 679 if (*p == '\0') 680 break; 681 682 base = p; 683 while (*p && *p != '=' && !isspace(*p)) 684 p++; 685 /* 686 * play it safe and keep it simple, bail if an opt name 687 * is too long. 688 */ 689 if ((p-base) >= sizeof (optname)) 690 return; 691 692 (void) strncpy(optname, base, p-base); 693 optname[p-base] = '\0'; 694 695 if (*p == '=') { 696 p++; 697 base = p; 698 while (*p && !isspace(*p)) 699 p++; 700 /* 701 * play it safe and keep it simple, bail if an opt 702 * value is too long. 703 */ 704 if ((p-base) >= sizeof (optval)) 705 return; 706 707 (void) strncpy(optval, base, p-base); 708 optval[p-base] = '\0'; 709 } else { 710 optval[0] = '\0'; 711 } 712 713 set_option(opt, optname, optval); 714 } 715 } 716 717 static 718 void 719 nss_get_environment() 720 { 721 char *p; 722 723 /* NSS_OPTIONS is undocumented and should be used without nscd running. */ 724 p = getenv("NSS_OPTIONS"); 725 if (p == NULL) 726 return; 727 __parse_environment(nss_options, p); 728 } 729 730 /* 731 * sole external routine called from libnsl/nis/cache/cache_api.cc in the 732 * routines _nis_CacheInit/__nis_CacheLocalInit/__nis_CacheMgrInit_discard 733 * Only after checking "checked_env" (which must be done with mutex 734 * "cur_cache_lock" held) and is done once, (then "checked_env" is set) 735 */ 736 void 737 __nis_get_environment() 738 { 739 char *p; 740 741 p = getenv("NIS_OPTIONS"); 742 if (p == NULL) 743 return; 744 __parse_environment(nis_options, p); 745 } 746 747 748 /* 749 * Switch policy component backend state machine functions 750 */ 751 752 static nss_backend_t * 753 nss_get_backend_u(nss_db_root_t **rootpp, struct nss_db_state *s, int n_src) 754 { 755 struct nss_src_state *src = &s->src[n_src]; 756 nss_backend_t *be; 757 int cancel_state; 758 759 for (;;) { 760 if (src->n_dormant > 0) { 761 src->n_dormant--; 762 src->n_active++; 763 if (s->p.max_dormant_per_src == 1) { 764 be = src->dormant.single; 765 } else { 766 be = src->dormant.multi[src->n_dormant]; 767 } 768 break; 769 } 770 771 if (src->be_constr == 0) { 772 nss_backend_finder_t *bf; 773 774 for (bf = s->p.finders; bf != 0; bf = bf->next) { 775 nss_backend_constr_t c; 776 777 c = (*bf->lookup) 778 (bf->lookup_priv, 779 s->p.name, 780 src->lkp->service_name, 781 &src->finder_priv); 782 if (c != 0) { 783 src->be_constr = c; 784 src->finder = bf; 785 break; 786 } 787 } 788 if (src->be_constr == 0) { 789 /* Couldn't find the backend anywhere */ 790 be = 0; 791 break; 792 } 793 } 794 795 if (src->n_active < s->p.max_active_per_src) { 796 be = (*src->be_constr)(s->p.name, 797 src->lkp->service_name, 798 0 /* === unimplemented */); 799 if (be != 0) { 800 src->n_active++; 801 break; 802 } else if (src->n_active == 0) { 803 /* Something's wrong; we should be */ 804 /* able to create at least one */ 805 /* instance of the backend */ 806 break; 807 } 808 /* 809 * Else it's odd that we can't create another backend 810 * instance, but don't sweat it; instead, queue for 811 * an existing backend instance. 812 */ 813 } 814 815 src->n_waiting++; 816 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 817 &cancel_state); 818 (void) cond_wait(&src->wanna_be, &(*rootpp)->lock); 819 (void) pthread_setcancelstate(cancel_state, NULL); 820 NSS_CHECKROOT(rootpp, s); 821 src->n_waiting--; 822 823 /* 824 * Loop and see whether things got better for us, or whether 825 * someone else got scheduled first and we have to try 826 * this again. 827 * 828 * === ?? Should count iterations, assume bug if many ?? 829 */ 830 } 831 return (be); 832 } 833 834 static void 835 nss_put_backend_u(struct nss_db_state *s, int n_src, nss_backend_t *be) 836 { 837 struct nss_src_state *src = &s->src[n_src]; 838 839 if (be == 0) { 840 return; 841 } 842 843 src->n_active--; 844 845 if (src->n_dormant < s->p.max_dormant_per_src) { 846 if (s->p.max_dormant_per_src == 1) { 847 src->dormant.single = be; 848 src->n_dormant++; 849 } else if (src->dormant.multi != 0 || 850 (src->dormant.multi = 851 libc_malloc(s->p.max_dormant_per_src * 852 sizeof (nss_backend_t *))) != NULL) { 853 src->dormant.multi[src->n_dormant] = be; 854 src->n_dormant++; 855 } else { 856 /* Can't store it, so toss it */ 857 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_DESTRUCTOR, 0); 858 } 859 } else { 860 /* We've stored as many as we want, so toss it */ 861 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_DESTRUCTOR, 0); 862 } 863 if (src->n_waiting > 0) { 864 (void) cond_signal(&src->wanna_be); 865 } 866 } 867 868 static struct nss_db_state * 869 _nss_db_state_constr(nss_db_initf_t initf) 870 { 871 struct nss_db_state *s; 872 struct __nsw_switchconfig_v1 *config = 0; 873 struct __nsw_lookup_v1 *lkp; 874 enum __nsw_parse_err err; 875 const char *config_name; 876 int n_src; 877 878 if ((s = libc_malloc(sizeof (*s))) == 0) { 879 return (0); 880 } 881 (void) _private_mutex_init(&s->orphan_root.lock, USYNC_THREAD, 0); 882 883 s->p.max_active_per_src = 10; 884 s->p.max_dormant_per_src = 1; 885 s->p.finders = nss_default_finders; 886 (*initf)(&s->p); 887 if (s->p.name == 0) { 888 _nss_db_state_destr(s); 889 return (0); 890 } 891 892 if (!checked_env) { 893 /* NSS_OPTIONS is undocumented and should be used without nscd running. */ 894 nss_get_environment(); 895 checked_env = 1; 896 } 897 898 config_name = s->p.config_name ? s->p.config_name : s->p.name; 899 if (! (s->p.flags & NSS_USE_DEFAULT_CONFIG)) { 900 config = __nsw_getconfig_v1(config_name, &err); 901 /* === ? test err ? */ 902 } 903 if (config == 0) { 904 /* getconfig failed, or frontend demanded default config */ 905 906 char *str; /* _nsw_getoneconfig() clobbers its argument */ 907 908 if ((str = libc_strdup(s->p.default_config)) != 0) { 909 config = _nsw_getoneconfig_v1(config_name, str, &err); 910 libc_free(str); 911 } 912 if (config == 0) { 913 _nss_db_state_destr(s); 914 return (0); 915 } 916 } 917 s->config = config; 918 if ((s->max_src = config->num_lookups) <= 0 || 919 (s->src = libc_malloc(s->max_src * sizeof (*s->src))) == 0) { 920 _nss_db_state_destr(s); 921 return (0); 922 } 923 for (n_src = 0, lkp = config->lookups; 924 n_src < s->max_src; n_src++, lkp = lkp->next) { 925 s->src[n_src].lkp = lkp; 926 (void) cond_init(&s->src[n_src].wanna_be, USYNC_THREAD, 0); 927 } 928 s->refcount = 1; 929 return (s); 930 } 931 932 void 933 _nss_src_state_destr(struct nss_src_state *src, int max_dormant) 934 { 935 if (max_dormant == 1) { 936 if (src->n_dormant != 0) { 937 (void) NSS_INVOKE_DBOP(src->dormant.single, 938 NSS_DBOP_DESTRUCTOR, 0); 939 }; 940 } else if (src->dormant.multi != 0) { 941 int n; 942 943 for (n = 0; n < src->n_dormant; n++) { 944 (void) NSS_INVOKE_DBOP(src->dormant.multi[n], 945 NSS_DBOP_DESTRUCTOR, 0); 946 } 947 libc_free(src->dormant.multi); 948 } 949 950 /* cond_destroy(&src->wanna_be); */ 951 952 if (src->finder != 0) { 953 (*src->finder->delete)(src->finder_priv, src->be_constr); 954 } 955 } 956 957 /* 958 * _nss_db_state_destr() -- used by NSS_UNREF_UNLOCK() to free the entire 959 * nss_db_state structure. 960 * Assumes that s has been ref-counted down to zero (in particular, 961 * rootp->s has already been dealt with). 962 * 963 * Nobody else holds a pointer to *s (if they did, refcount != 0), 964 * so we can clean up state *after* we drop the lock (also, by the 965 * time we finish freeing the state structures, the lock may have 966 * ceased to exist -- if we were using the orphan_root). 967 */ 968 969 void 970 _nss_db_state_destr(struct nss_db_state *s) 971 { 972 973 if (s == NULL) 974 return; 975 976 /* === _private_mutex_destroy(&s->orphan_root.lock); */ 977 if (s->p.cleanup != 0) { 978 (*s->p.cleanup)(&s->p); 979 } 980 if (s->config != 0) { 981 (void) __nsw_freeconfig_v1(s->config); 982 } 983 if (s->src != 0) { 984 int n_src; 985 986 for (n_src = 0; n_src < s->max_src; n_src++) { 987 _nss_src_state_destr(&s->src[n_src], 988 s->p.max_dormant_per_src); 989 } 990 libc_free(s->src); 991 } 992 libc_free(s); 993 } 994 995 996 /* 997 * _nss_status_vec() returns a bit vector of all status codes returned during 998 * the most recent call to nss_search(). 999 * _nss_status_vec_p() returns a pointer to this bit vector, or NULL on 1000 * failure. 1001 * These functions are private. Don't use them externally without discussing 1002 * it with the switch maintainers. 1003 */ 1004 static uint_t * 1005 _nss_status_vec_p() 1006 { 1007 return (tsdalloc(_T_NSS_STATUS_VEC, sizeof (uint_t), NULL)); 1008 } 1009 1010 unsigned int 1011 _nss_status_vec(void) 1012 { 1013 unsigned int *status_vec_p = _nss_status_vec_p(); 1014 1015 return ((status_vec_p != NULL) ? *status_vec_p : (1 << NSS_UNAVAIL)); 1016 } 1017 1018 static void 1019 output_loop_diag_a( 1020 int n, 1021 char *dbase, 1022 struct __nsw_lookup_v1 *lkp) 1023 1024 { 1025 (void) fprintf(__nss_debug_file, 1026 "NSS_retry(%d): '%s': trying '%s' ... ", 1027 n, dbase, lkp->service_name); 1028 (void) fflush(__nss_debug_file); 1029 1030 } 1031 1032 static void 1033 output_loop_diag_b( 1034 nss_status_t res, 1035 struct __nsw_lookup_v1 *lkp) 1036 1037 { 1038 (void) fprintf(__nss_debug_file, "result="); 1039 switch (res) { 1040 case NSS_SUCCESS: 1041 (void) fprintf(__nss_debug_file, "SUCCESS"); 1042 break; 1043 case NSS_NOTFOUND: 1044 (void) fprintf(__nss_debug_file, "NOTFOUND"); 1045 break; 1046 case NSS_UNAVAIL: 1047 (void) fprintf(__nss_debug_file, "UNAVAIL"); 1048 break; 1049 case NSS_TRYAGAIN: 1050 (void) fprintf(__nss_debug_file, "TRYAGAIN"); 1051 break; 1052 case NSS_NISSERVDNS_TRYAGAIN: 1053 (void) fprintf(__nss_debug_file, "NISSERVDNS_TRYAGAIN"); 1054 break; 1055 default: 1056 (void) fprintf(__nss_debug_file, "undefined"); 1057 } 1058 (void) fprintf(__nss_debug_file, ", action="); 1059 switch (lkp->actions[res]) { 1060 case __NSW_CONTINUE: 1061 (void) fprintf(__nss_debug_file, "CONTINUE"); 1062 break; 1063 case __NSW_RETURN: 1064 (void) fprintf(__nss_debug_file, "RETURN"); 1065 break; 1066 case __NSW_TRYAGAIN_FOREVER: 1067 (void) fprintf(__nss_debug_file, "TRYAGAIN_FOREVER"); 1068 break; 1069 case __NSW_TRYAGAIN_NTIMES: 1070 (void) fprintf(__nss_debug_file, "TRYAGAIN_NTIMES (N=%d)", 1071 lkp->max_retries); 1072 break; 1073 case __NSW_TRYAGAIN_PAUSED: 1074 (void) fprintf(__nss_debug_file, "TRYAGAIN_PAUSED"); 1075 break; 1076 default: 1077 (void) fprintf(__nss_debug_file, "undefined"); 1078 } 1079 (void) fprintf(__nss_debug_file, "\n"); 1080 } 1081 1082 #define NSS_BACKOFF(n, b, t) \ 1083 ((n) > ((b) + 3) ? t : (1 << ((n) - ((b) + 1)))) 1084 1085 static int 1086 retry_test(nss_status_t res, int n, struct __nsw_lookup_v1 *lkp) 1087 { 1088 if (res != NSS_TRYAGAIN && res != NSS_NISSERVDNS_TRYAGAIN) { 1089 if (res == NSS_SUCCESS) { 1090 __NSW_UNPAUSE_ACTION(lkp->actions[__NSW_TRYAGAIN]); 1091 __NSW_UNPAUSE_ACTION( 1092 lkp->actions[__NSW_NISSERVDNS_TRYAGAIN]); 1093 } 1094 return (0); 1095 } 1096 1097 if ((res == NSS_TRYAGAIN && 1098 lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER) || 1099 (res == NSS_NISSERVDNS_TRYAGAIN && 1100 lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER)) 1101 return (1); 1102 1103 if (res == NSS_TRYAGAIN && 1104 lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES) 1105 if (n <= lkp->max_retries) 1106 return (1); 1107 else { 1108 lkp->actions[__NSW_TRYAGAIN] = __NSW_TRYAGAIN_PAUSED; 1109 return (0); 1110 } 1111 1112 if (res == NSS_NISSERVDNS_TRYAGAIN && 1113 lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES) 1114 if (n <= lkp->max_retries) 1115 return (1); 1116 else { 1117 lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] = 1118 __NSW_TRYAGAIN_PAUSED; 1119 return (0); 1120 } 1121 1122 return (0); 1123 } 1124 1125 /* 1126 * Switch policy component functional interfaces 1127 */ 1128 1129 void 1130 nss_delete(nss_db_root_t *rootp) 1131 { 1132 struct nss_db_state *s; 1133 1134 /* no name service cache daemon divert here */ 1135 /* local nss_delete decrements state reference counts */ 1136 /* and may free up opened switch resources. */ 1137 1138 NSS_ROOTLOCK(rootp, &s); 1139 if (s == 0) { 1140 NSS_UNLOCK(rootp); 1141 } else { 1142 rootp->s = 0; 1143 NSS_UNREF_UNLOCK(rootp, s); 1144 } 1145 } 1146 1147 nss_status_t 1148 nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum, 1149 void *search_args) 1150 { 1151 nss_status_t res = NSS_UNAVAIL; 1152 struct nss_db_state *s; 1153 int n_src; 1154 unsigned int *status_vec_p; 1155 1156 /* name service cache daemon divert */ 1157 res = _nsc_search(rootp, initf, search_fnum, search_args); 1158 if (res != NSS_TRYLOCAL) 1159 return (res); 1160 1161 /* fall through - process locally */ 1162 errno = 0; /* just in case ... */ 1163 res = NSS_UNAVAIL; 1164 status_vec_p = _nss_status_vec_p(); 1165 1166 if (status_vec_p == NULL) { 1167 return (NSS_UNAVAIL); 1168 } 1169 *status_vec_p = 0; 1170 1171 NSS_LOCK_CHECK(rootp, initf, &s); 1172 if (s == 0) { 1173 NSS_UNLOCK(rootp); 1174 return (res); 1175 } 1176 NSS_STATE_REF_u(s); 1177 1178 for (n_src = 0; n_src < s->max_src; n_src++) { 1179 nss_backend_t *be; 1180 nss_backend_op_t funcp; 1181 1182 res = NSS_UNAVAIL; 1183 if ((be = nss_get_backend_u(&rootp, s, n_src)) != 0) { 1184 if ((funcp = NSS_LOOKUP_DBOP(be, search_fnum)) != 0) { 1185 int n_loop = 0; 1186 int no_backoff = 19; 1187 int max_backoff = 5; /* seconds */ 1188 1189 do { 1190 /* 1191 * Backend operation may take a while; 1192 * drop the lock so we don't serialize 1193 * more than necessary. 1194 */ 1195 NSS_UNLOCK(rootp); 1196 1197 /* After several tries, backoff... */ 1198 if (n_loop > no_backoff) { 1199 if (__nss_debug_eng_loop > 1) 1200 (void) fprintf(__nss_debug_file, 1201 "NSS: loop: sleeping %d ...\n", 1202 NSS_BACKOFF(n_loop, 1203 no_backoff, max_backoff)); 1204 1205 (void) sleep(NSS_BACKOFF(n_loop, 1206 no_backoff, max_backoff)); 1207 } 1208 1209 if (__nss_debug_eng_loop) 1210 output_loop_diag_a(n_loop, 1211 s->config->dbase, 1212 s->src[n_src].lkp); 1213 1214 1215 res = (*funcp)(be, search_args); 1216 NSS_RELOCK(&rootp, s); 1217 n_loop++; 1218 if (__nss_debug_eng_loop) 1219 output_loop_diag_b(res, 1220 s->src[n_src].lkp); 1221 } while (retry_test(res, n_loop, 1222 s->src[n_src].lkp)); 1223 } 1224 nss_put_backend_u(s, n_src, be); 1225 } 1226 *status_vec_p |= (1 << res); 1227 if (__NSW_ACTION_V1(s->src[n_src].lkp, res) == __NSW_RETURN) { 1228 if (__nss_debug_eng_loop) 1229 (void) fprintf(__nss_debug_file, 1230 "NSS: '%s': return.\n", 1231 s->config->dbase); 1232 break; 1233 } else 1234 if (__nss_debug_eng_loop) 1235 (void) fprintf(__nss_debug_file, 1236 "NSS: '%s': continue ...\n", 1237 s->config->dbase); 1238 } 1239 NSS_UNREF_UNLOCK(rootp, s); 1240 return (res); 1241 } 1242 1243 1244 /* 1245 * Start of nss_{setent|getent|endent} 1246 */ 1247 1248 /* 1249 * State (here called "context") for one setent/getent.../endent sequence. 1250 * In principle there could be multiple contexts active for a single 1251 * database; in practice, since Posix and UI have helpfully said that 1252 * getent() state is global rather than, say, per-thread or user-supplied, 1253 * we have at most one of these per nss_db_state. 1254 * XXX ? Is this statement still true? 1255 * 1256 * NSS2 - a client's context is maintained as a cookie delivered by and 1257 * passed to nscd. The cookie is a 64 bit (nssuint_t) unique opaque value 1258 * created by nscd. 1259 * cookie states: 1260 * NSCD_NEW_COOKIE - cookie value uninitialized 1261 * NSCD_LOCAL_COOKIE - setent is a local setent 1262 * all other - NSCD unique opaque id for this setent 1263 * A client's context is also associated with a seq_num. This is a nscd 1264 * opaque 64 bit (nssuint_t) value passed with a cookie, and used to by nscd 1265 * to validate the sequencing of the context. The client treats this as 1266 * a pass through value. 1267 * 1268 * XXX ?? Use Cookie as cross-check info so that we can detect an 1269 * nss_context that missed an nss_delete() or similar. 1270 */ 1271 1272 struct nss_getent_context { 1273 int n_src; /* >= max_src ==> end of sequence */ 1274 nss_backend_t *be; 1275 struct nss_db_state *s; 1276 nssuint_t cookie; 1277 nssuint_t seq_num; 1278 nssuint_t cookie_setent; 1279 nss_db_params_t param; 1280 }; 1281 1282 static void nss_setent_u(nss_db_root_t *, 1283 nss_db_initf_t, 1284 nss_getent_t *); 1285 static nss_status_t nss_getent_u(nss_db_root_t *, 1286 nss_db_initf_t, 1287 nss_getent_t *, 1288 void *); 1289 static void nss_endent_u(nss_db_root_t *, 1290 nss_db_initf_t, 1291 nss_getent_t *); 1292 1293 void 1294 nss_setent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp) 1295 { 1296 if (contextpp == 0) { 1297 return; 1298 } 1299 cancel_safe_mutex_lock(&contextpp->lock); 1300 nss_setent_u(rootp, initf, contextpp); 1301 cancel_safe_mutex_unlock(&contextpp->lock); 1302 } 1303 1304 nss_status_t 1305 nss_getent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp, 1306 void *args) 1307 { 1308 nss_status_t status; 1309 1310 if (contextpp == 0) { 1311 return (NSS_UNAVAIL); 1312 } 1313 cancel_safe_mutex_lock(&contextpp->lock); 1314 status = nss_getent_u(rootp, initf, contextpp, args); 1315 cancel_safe_mutex_unlock(&contextpp->lock); 1316 return (status); 1317 } 1318 1319 void 1320 nss_endent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp) 1321 { 1322 if (contextpp == 0) { 1323 return; 1324 } 1325 cancel_safe_mutex_lock(&contextpp->lock); 1326 nss_endent_u(rootp, initf, contextpp); 1327 cancel_safe_mutex_unlock(&contextpp->lock); 1328 } 1329 1330 /* 1331 * Each of the _u versions of the nss interfaces assume that the context 1332 * lock is held. No need to divert to nscd. Private to local sequencing. 1333 */ 1334 1335 static void 1336 end_iter_u(nss_db_root_t *rootp, struct nss_getent_context *contextp) 1337 { 1338 struct nss_db_state *s; 1339 nss_backend_t *be; 1340 int n_src; 1341 1342 s = contextp->s; 1343 n_src = contextp->n_src; 1344 be = contextp->be; 1345 1346 if (s != 0) { 1347 if (n_src < s->max_src && be != 0) { 1348 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0); 1349 NSS_RELOCK(&rootp, s); 1350 nss_put_backend_u(s, n_src, be); 1351 contextp->be = 0; /* Should be unnecessary, but hey */ 1352 NSS_UNREF_UNLOCK(rootp, s); 1353 } 1354 contextp->s = 0; 1355 } 1356 } 1357 1358 static void 1359 nss_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf, 1360 nss_getent_t *contextpp) 1361 { 1362 nss_status_t status; 1363 struct nss_db_state *s; 1364 struct nss_getent_context *contextp; 1365 nss_backend_t *be; 1366 int n_src; 1367 1368 /* setup process wide context while locked */ 1369 if ((contextp = contextpp->ctx) == 0) { 1370 if ((contextp = libc_malloc(sizeof (*contextp))) == 0) { 1371 return; 1372 } 1373 contextpp->ctx = contextp; 1374 contextp->cookie = NSCD_NEW_COOKIE; /* cookie init */ 1375 contextp->seq_num = 0; /* seq_num init */ 1376 s = 0; 1377 } else { 1378 s = contextp->s; 1379 if (contextp->cookie != NSCD_LOCAL_COOKIE) 1380 contextp->cookie = NSCD_NEW_COOKIE; 1381 } 1382 1383 /* name service cache daemon divert */ 1384 if (contextp->cookie == NSCD_NEW_COOKIE) { 1385 status = _nsc_setent_u(rootp, initf, contextpp); 1386 if (status != NSS_TRYLOCAL) 1387 return; 1388 } 1389 1390 /* fall through - process locally */ 1391 if (s == 0) { 1392 NSS_LOCK_CHECK(rootp, initf, &s); 1393 if (s == 0) { 1394 /* Couldn't set up state, so quit */ 1395 NSS_UNLOCK(rootp); 1396 /* ==== is there any danger of not having done an */ 1397 /* end_iter() here, and hence of losing backends? */ 1398 contextpp->ctx = 0; 1399 libc_free(contextp); 1400 return; 1401 } 1402 NSS_STATE_REF_u(s); 1403 contextp->s = s; 1404 } else { 1405 s = contextp->s; 1406 n_src = contextp->n_src; 1407 be = contextp->be; 1408 if (n_src == 0 && be != 0) { 1409 /* 1410 * Optimization: don't do endent, don't change 1411 * backends, just do the setent. Look Ma, no locks 1412 * (nor any context that needs updating). 1413 */ 1414 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0); 1415 return; 1416 } 1417 if (n_src < s->max_src && be != 0) { 1418 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0); 1419 NSS_RELOCK(&rootp, s); 1420 nss_put_backend_u(s, n_src, be); 1421 contextp->be = 0; /* Play it safe */ 1422 } else { 1423 NSS_RELOCK(&rootp, s); 1424 } 1425 } 1426 for (n_src = 0, be = 0; n_src < s->max_src && 1427 (be = nss_get_backend_u(&rootp, s, n_src)) == 0; n_src++) { 1428 ; 1429 } 1430 NSS_UNLOCK(rootp); 1431 1432 contextp->n_src = n_src; 1433 contextp->be = be; 1434 1435 if (be == 0) { 1436 /* Things are broken enough that we can't do setent/getent */ 1437 nss_endent_u(rootp, initf, contextpp); 1438 return; 1439 } 1440 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0); 1441 } 1442 1443 static nss_status_t 1444 nss_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf, 1445 nss_getent_t *contextpp, void *args) 1446 { 1447 nss_status_t status; 1448 struct nss_db_state *s; 1449 struct nss_getent_context *contextp; 1450 int n_src; 1451 nss_backend_t *be; 1452 1453 if ((contextp = contextpp->ctx) == 0) { 1454 nss_setent_u(rootp, initf, contextpp); 1455 if ((contextp = contextpp->ctx) == 0) { 1456 /* Give up */ 1457 return (NSS_UNAVAIL); 1458 } 1459 } 1460 /* name service cache daemon divert */ 1461 status = _nsc_getent_u(rootp, initf, contextpp, args); 1462 if (status != NSS_TRYLOCAL) 1463 return (status); 1464 1465 /* fall through - process locally */ 1466 s = contextp->s; 1467 n_src = contextp->n_src; 1468 be = contextp->be; 1469 1470 if (s == 0) { 1471 /* 1472 * We've done an end_iter() and haven't done nss_setent() 1473 * or nss_endent() since; we should stick in this state 1474 * until the caller invokes one of those two routines. 1475 */ 1476 return (NSS_SUCCESS); 1477 } 1478 1479 while (n_src < s->max_src) { 1480 nss_status_t res; 1481 1482 if (be == 0) { 1483 /* If it's null it's a bug, but let's play safe */ 1484 res = NSS_UNAVAIL; 1485 } else { 1486 res = NSS_INVOKE_DBOP(be, NSS_DBOP_GETENT, args); 1487 } 1488 1489 if (__NSW_ACTION_V1(s->src[n_src].lkp, res) == __NSW_RETURN) { 1490 if (res != __NSW_SUCCESS) { 1491 end_iter_u(rootp, contextp); 1492 } 1493 return (res); 1494 } 1495 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0); 1496 NSS_RELOCK(&rootp, s); 1497 nss_put_backend_u(s, n_src, be); 1498 do { 1499 n_src++; 1500 } while (n_src < s->max_src && 1501 (be = nss_get_backend_u(&rootp, s, n_src)) == 0); 1502 if (be == 0) { 1503 /* 1504 * This is the case where we failed to get the backend 1505 * for the last source. We exhausted all sources. 1506 */ 1507 NSS_UNLOCK(rootp); 1508 nss_endent_u(rootp, initf, contextpp); 1509 nss_delete(rootp); 1510 return (NSS_SUCCESS); 1511 } 1512 NSS_UNLOCK(rootp); 1513 contextp->n_src = n_src; 1514 contextp->be = be; 1515 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0); 1516 } 1517 /* Got to the end of the sources without finding another entry */ 1518 end_iter_u(rootp, contextp); 1519 return (NSS_SUCCESS); 1520 /* success is either a successful entry or end of the sources */ 1521 } 1522 1523 /*ARGSUSED*/ 1524 static void 1525 nss_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf, 1526 nss_getent_t *contextpp) 1527 { 1528 nss_status_t status; 1529 struct nss_getent_context *contextp; 1530 1531 if ((contextp = contextpp->ctx) == 0) { 1532 /* nss_endent() on an unused context is a no-op */ 1533 return; 1534 } 1535 1536 /* notify name service cache daemon */ 1537 status = _nsc_endent_u(rootp, initf, contextpp); 1538 if (status != NSS_TRYLOCAL) { 1539 /* clean up */ 1540 libc_free(contextp); 1541 contextpp->ctx = 0; 1542 return; 1543 } 1544 1545 /* fall through - process locally */ 1546 1547 /* 1548 * Existing code (BSD, SunOS) works in such a way that getXXXent() 1549 * following an endXXXent() behaves as though the user had invoked 1550 * setXXXent(), i.e. it iterates properly from the beginning. 1551 * We'd better not break this, so our choices are 1552 * (1) leave the context structure around, and do nss_setent or 1553 * something equivalent, 1554 * or (2) free the context completely, and rely on the code in 1555 * nss_getent() that makes getXXXent() do the right thing 1556 * even without a preceding setXXXent(). 1557 * The code below does (2), which frees up resources nicely but will 1558 * cost more if the user then does more getXXXent() operations. 1559 * Moral: for efficiency, don't call endXXXent() prematurely. 1560 */ 1561 end_iter_u(rootp, contextp); 1562 libc_free(contextp); 1563 contextpp->ctx = 0; 1564 } 1565 1566 /* 1567 * pack dbd data into header 1568 * Argment pointers assumed valid. 1569 * poff offset position pointer 1570 * IN = starting offset for dbd header 1571 * OUT = starting offset for next section 1572 */ 1573 1574 static nss_status_t 1575 nss_pack_dbd(void *buffer, size_t bufsize, nss_db_params_t *p, size_t *poff) 1576 { 1577 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1578 nss_dbd_t *pdbd; 1579 size_t off = *poff; 1580 size_t len, blen; 1581 size_t n, nc, dc; 1582 char *bptr; 1583 1584 pbuf->dbd_off = (nssuint_t)off; 1585 bptr = (char *)buffer + off; 1586 blen = bufsize - off; 1587 len = sizeof (nss_dbd_t); 1588 1589 n = nc = dc = 0; 1590 if (p->name == NULL) { 1591 errno = ERANGE; /* actually EINVAL */ 1592 return (NSS_ERROR); 1593 } 1594 1595 /* if default config not specified, the flag should be reset */ 1596 if (p->default_config == NULL) { 1597 p->default_config = "<NULL>"; 1598 p->flags = p->flags & ~NSS_USE_DEFAULT_CONFIG; 1599 } 1600 1601 n = strlen(p->name) + 1; 1602 dc = strlen(p->default_config) + 1; 1603 if (n < 2 || dc < 2) { /* What no DB? */ 1604 errno = ERANGE; /* actually EINVAL */ 1605 return (NSS_ERROR); 1606 } 1607 if (p->config_name != NULL) { 1608 nc = strlen(p->config_name) + 1; 1609 } 1610 if ((len + n + nc + dc) >= blen) { 1611 errno = ERANGE; /* actually EINVAL */ 1612 return (NSS_ERROR); 1613 } 1614 1615 pdbd = (nss_dbd_t *)((void *)bptr); 1616 bptr += len; 1617 pdbd->flags = p->flags; 1618 pdbd->o_name = len; 1619 (void) strlcpy(bptr, p->name, n); 1620 len += n; 1621 bptr += n; 1622 if (nc == 0) { 1623 pdbd->o_config_name = 0; 1624 } else { 1625 pdbd->o_config_name = len; 1626 (void) strlcpy(bptr, p->config_name, nc); 1627 bptr += nc; 1628 len += nc; 1629 } 1630 pdbd->o_default_config = len; 1631 (void) strlcpy(bptr, p->default_config, dc); 1632 len += dc; 1633 pbuf->dbd_len = (nssuint_t)len; 1634 off += ROUND_UP(len, sizeof (nssuint_t)); 1635 *poff = off; 1636 return (NSS_SUCCESS); 1637 } 1638 1639 /* 1640 * Switch packed and _nsc (switch->nscd) interfaces 1641 * Return: NSS_SUCCESS (OK to proceed), NSS_ERROR, NSS_NOTFOUND 1642 */ 1643 1644 /*ARGSUSED*/ 1645 nss_status_t 1646 nss_pack(void *buffer, size_t bufsize, nss_db_root_t *rootp, 1647 nss_db_initf_t initf, int search_fnum, void *search_args) 1648 { 1649 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1650 nss_XbyY_args_t *in = (nss_XbyY_args_t *)search_args; 1651 nss_db_params_t tparam = { 0 }; 1652 nss_status_t ret = NSS_ERROR; 1653 const char *dbn; 1654 size_t blen, len, off = 0; 1655 char *bptr; 1656 struct nss_groupsbymem *gbm; 1657 1658 if (pbuf == NULL || in == NULL || initf == (nss_db_initf_t)NULL) { 1659 errno = ERANGE; /* actually EINVAL */ 1660 return (ret); 1661 } 1662 tparam.cleanup = NULL; 1663 (*initf)(&tparam); 1664 if ((dbn = tparam.name) == 0) { 1665 if (tparam.cleanup != 0) 1666 (tparam.cleanup)(&tparam); 1667 errno = ERANGE; /* actually EINVAL */ 1668 return (ret); 1669 } 1670 1671 /* init buffer header */ 1672 pbuf->pbufsiz = (nssuint_t)bufsize; 1673 pbuf->p_ruid = (uint32_t)getuid(); 1674 pbuf->p_euid = (uint32_t)geteuid(); 1675 pbuf->p_version = NSCD_HEADER_REV; 1676 pbuf->p_status = 0; 1677 pbuf->p_errno = 0; 1678 pbuf->p_herrno = 0; 1679 1680 /* possible audituser init */ 1681 if (strcmp(dbn, NSS_DBNAM_AUTHATTR) == 0 && in->h_errno != 0) 1682 pbuf->p_herrno = (uint32_t)in->h_errno; 1683 1684 pbuf->libpriv = 0; 1685 1686 off = sizeof (nss_pheader_t); 1687 1688 /* setup getXbyY operation - database and sub function */ 1689 pbuf->nss_dbop = (uint32_t)search_fnum; 1690 ret = nss_pack_dbd(buffer, bufsize, &tparam, &off); 1691 if (ret != NSS_SUCCESS) { 1692 errno = ERANGE; /* actually EINVAL */ 1693 return (ret); 1694 } 1695 ret = NSS_ERROR; 1696 /* setup request key */ 1697 pbuf->key_off = (nssuint_t)off; 1698 bptr = (char *)buffer + off; 1699 blen = bufsize - off; 1700 /* use key2str if provided, else call default getXbyY packer */ 1701 if (strcmp(dbn, NSS_DBNAM_NETGROUP) == 0) { 1702 /* This has to run locally due to backend knowledge */ 1703 if (search_fnum == NSS_DBOP_NETGROUP_SET) { 1704 errno = 0; 1705 return (NSS_TRYLOCAL); 1706 } 1707 /* use default packer for known getXbyY ops */ 1708 ret = nss_default_key2str(bptr, blen, in, dbn, 1709 search_fnum, &len); 1710 } else if (in->key2str == NULL || 1711 (search_fnum == NSS_DBOP_GROUP_BYMEMBER && 1712 strcmp(dbn, NSS_DBNAM_GROUP) == 0)) { 1713 /* use default packer for known getXbyY ops */ 1714 ret = nss_default_key2str(bptr, blen, in, dbn, 1715 search_fnum, &len); 1716 } else { 1717 ret = (*in->key2str)(bptr, blen, &in->key, &len); 1718 } 1719 if (tparam.cleanup != 0) 1720 (tparam.cleanup)(&tparam); 1721 if (ret != NSS_SUCCESS) { 1722 errno = ERANGE; /* actually ENOMEM */ 1723 return (ret); 1724 } 1725 pbuf->key_len = (nssuint_t)len; 1726 off += ROUND_UP(len, sizeof (nssuint_t)); 1727 1728 pbuf->data_off = (nssuint_t)off; 1729 pbuf->data_len = (nssuint_t)(bufsize - off); 1730 /* 1731 * Prime data return with first result if 1732 * the first result is passed in 1733 * [_getgroupsbymember oddness] 1734 */ 1735 gbm = (struct nss_groupsbymem *)search_args; 1736 if (search_fnum == NSS_DBOP_GROUP_BYMEMBER && 1737 strcmp(dbn, NSS_DBNAM_GROUP) == 0 && gbm->numgids == 1) { 1738 gid_t *gidp; 1739 gidp = (gid_t *)((void *)((char *)buffer + off)); 1740 *gidp = gbm->gid_array[0]; 1741 } 1742 1743 errno = 0; /* just in case ... */ 1744 return (NSS_SUCCESS); 1745 } 1746 1747 /* 1748 * Switch packed and _nsc (switch->nscd) {set/get/end}ent interfaces 1749 * Return: NSS_SUCCESS (OK to proceed), NSS_ERROR, NSS_NOTFOUND 1750 */ 1751 1752 /*ARGSUSED*/ 1753 nss_status_t 1754 nss_pack_ent(void *buffer, size_t bufsize, nss_db_root_t *rootp, 1755 nss_db_initf_t initf, nss_getent_t *contextpp) 1756 { 1757 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1758 struct nss_getent_context *contextp = contextpp->ctx; 1759 nss_status_t ret = NSS_ERROR; 1760 size_t blen, len = 0, off = 0; 1761 char *bptr; 1762 nssuint_t *nptr; 1763 1764 if (pbuf == NULL || initf == (nss_db_initf_t)NULL) { 1765 errno = ERANGE; /* actually EINVAL */ 1766 return (ret); 1767 } 1768 1769 /* init buffer header */ 1770 pbuf->pbufsiz = (nssuint_t)bufsize; 1771 pbuf->p_ruid = (uint32_t)getuid(); 1772 pbuf->p_euid = (uint32_t)geteuid(); 1773 pbuf->p_version = NSCD_HEADER_REV; 1774 pbuf->p_status = 0; 1775 pbuf->p_errno = 0; 1776 pbuf->p_herrno = 0; 1777 pbuf->libpriv = 0; 1778 1779 off = sizeof (nss_pheader_t); 1780 1781 /* setup getXXXent operation - database and sub function */ 1782 pbuf->nss_dbop = (uint32_t)0; /* iterators have no dbop */ 1783 ret = nss_pack_dbd(buffer, bufsize, &contextp->param, &off); 1784 if (ret != NSS_SUCCESS) { 1785 errno = ERANGE; /* actually EINVAL */ 1786 return (ret); 1787 } 1788 ret = NSS_ERROR; 1789 off += ROUND_UP(len, sizeof (nssuint_t)); 1790 1791 pbuf->key_off = (nssuint_t)off; 1792 bptr = (char *)buffer + off; 1793 blen = bufsize - off; 1794 len = (size_t)(sizeof (nssuint_t) * 2); 1795 if (len >= blen) { 1796 errno = ERANGE; /* actually EINVAL */ 1797 return (ret); 1798 } 1799 nptr = (nssuint_t *)((void *)bptr); 1800 *nptr++ = contextp->cookie; 1801 *nptr = contextp->seq_num; 1802 pbuf->key_len = (nssuint_t)len; 1803 1804 off += len; 1805 pbuf->data_off = (nssuint_t)off; 1806 pbuf->data_len = (nssuint_t)(bufsize - off); 1807 return (NSS_SUCCESS); 1808 } 1809 1810 /* 1811 * Unpack packed arguments buffer 1812 * Return: status, errnos and results from requested operation. 1813 * 1814 * NOTES: When getgroupsbymember is being processed in the NSCD backend, 1815 * or via the backwards compatibility interfaces then the standard 1816 * str2group API is used in conjunction with process_cstr. When, 1817 * processing a returned buffer, in NSS2 the return results are the 1818 * already digested groups array. Therefore, unpack the digested results 1819 * back to the return buffer. 1820 * 1821 * Note: the digested results are nssuint_t quantities. _getgroupsbymember 1822 * digests int quantities. Therefore convert. Assume input is in nssuint_t 1823 * quantities. Store in an int array... Assume gid's are <= 32 bits... 1824 */ 1825 1826 /*ARGSUSED*/ 1827 nss_status_t 1828 nss_unpack(void *buffer, size_t bufsize, nss_db_root_t *rootp, 1829 nss_db_initf_t initf, int search_fnum, void *search_args) 1830 { 1831 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1832 nss_XbyY_args_t *in = (nss_XbyY_args_t *)search_args; 1833 nss_dbd_t *pdbd; 1834 char *dbn; 1835 nss_status_t status; 1836 char *buf; 1837 int len; 1838 int ret; 1839 int i; 1840 int fmt_type; 1841 gid_t *gidp; 1842 gid_t *gptr; 1843 struct nss_groupsbymem *arg; 1844 1845 1846 if (pbuf == NULL || in == NULL) 1847 return (-1); 1848 status = pbuf->p_status; 1849 /* Identify odd cases */ 1850 pdbd = (nss_dbd_t *)((void *)((char *)buffer + pbuf->dbd_off)); 1851 dbn = (char *)pdbd + pdbd->o_name; 1852 fmt_type = 0; /* nss_XbyY_args_t */ 1853 if (search_fnum == NSS_DBOP_GROUP_BYMEMBER && 1854 strcmp(dbn, NSS_DBNAM_GROUP) == 0) 1855 fmt_type = 1; /* struct nss_groupsbymem */ 1856 else if (search_fnum == NSS_DBOP_NETGROUP_IN && 1857 strcmp(dbn, NSS_DBNAM_NETGROUP) == 0) 1858 fmt_type = 2; /* struct nss_innetgr_args */ 1859 1860 /* if error - door's switch error */ 1861 /* extended data could contain additional information? */ 1862 if (status != NSS_SUCCESS) { 1863 if (fmt_type == 0) { 1864 in->h_errno = (int)pbuf->p_herrno; 1865 if (pbuf->p_errno == ERANGE) 1866 in->erange = 1; 1867 } 1868 return (status); 1869 } 1870 1871 if (pbuf->data_off == 0 || pbuf->data_len == 0) 1872 return (NSS_NOTFOUND); 1873 1874 buf = (char *)buffer + pbuf->data_off; 1875 len = pbuf->data_len; 1876 1877 /* sidestep odd cases */ 1878 if (fmt_type == 1) { 1879 arg = (struct nss_groupsbymem *)in; 1880 /* copy returned gid array from returned nscd buffer */ 1881 i = len / sizeof (gid_t); 1882 /* not enough buffer */ 1883 if (i > arg->maxgids) { 1884 i = arg->maxgids; 1885 } 1886 arg->numgids = i; 1887 gidp = arg->gid_array; 1888 gptr = (gid_t *)((void *)buf); 1889 memcpy(gidp, gptr, len); 1890 return (NSS_SUCCESS); 1891 } 1892 if (fmt_type == 2) { 1893 struct nss_innetgr_args *arg = (struct nss_innetgr_args *)in; 1894 1895 if (pbuf->p_status == NSS_SUCCESS) { 1896 arg->status = NSS_NETGR_FOUND; 1897 return (NSS_SUCCESS); 1898 } else { 1899 arg->status = NSS_NETGR_NO; 1900 return (NSS_NOTFOUND); 1901 } 1902 } 1903 1904 /* process the normal cases */ 1905 /* marshall data directly into users buffer */ 1906 ret = (*in->str2ent)(buf, len, in->buf.result, in->buf.buffer, 1907 in->buf.buflen); 1908 if (ret == NSS_STR_PARSE_ERANGE) { 1909 in->returnval = 0; 1910 in->returnlen = 0; 1911 in->erange = 1; 1912 ret = NSS_NOTFOUND; 1913 } else if (ret == NSS_STR_PARSE_SUCCESS) { 1914 in->returnval = in->buf.result; 1915 in->returnlen = len; 1916 ret = NSS_SUCCESS; 1917 } 1918 in->h_errno = (int)pbuf->p_herrno; 1919 return ((nss_status_t)ret); 1920 } 1921 1922 /* 1923 * Unpack a returned packed {set,get,end}ent arguments buffer 1924 * Return: status, errnos, cookie info and results from requested operation. 1925 */ 1926 1927 /*ARGSUSED*/ 1928 nss_status_t 1929 nss_unpack_ent(void *buffer, size_t bufsize, nss_db_root_t *rootp, 1930 nss_db_initf_t initf, nss_getent_t *contextpp, void *args) 1931 { 1932 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1933 nss_XbyY_args_t *in = (nss_XbyY_args_t *)args; 1934 struct nss_getent_context *contextp = contextpp->ctx; 1935 nssuint_t *nptr; 1936 nssuint_t cookie; 1937 nss_status_t status; 1938 char *buf; 1939 int len; 1940 int ret; 1941 1942 if (pbuf == NULL) 1943 return (-1); 1944 status = pbuf->p_status; 1945 /* if error - door's switch error */ 1946 /* extended data could contain additional information? */ 1947 if (status != NSS_SUCCESS) 1948 return (status); 1949 1950 /* unpack assigned cookie from SET/GET/END request */ 1951 if (pbuf->key_off == 0 || 1952 pbuf->key_len != (sizeof (nssuint_t) * 2)) 1953 return (NSS_NOTFOUND); 1954 1955 nptr = (nssuint_t *)((void *)((char *)buffer + pbuf->key_off)); 1956 cookie = contextp->cookie; 1957 if (cookie != NSCD_NEW_COOKIE && cookie != contextp->cookie_setent && 1958 cookie != *nptr) { 1959 /* 1960 * Should either be new, or the cookie returned by the last 1961 * setent (i.e., this is the first getent after the setent) 1962 * or a match, else error 1963 */ 1964 return (NSS_NOTFOUND); 1965 } 1966 /* save away for the next ent request */ 1967 contextp->cookie = *nptr++; 1968 contextp->seq_num = *nptr; 1969 1970 /* All done if no marshalling is expected {set,end}ent */ 1971 if (args == NULL) 1972 return (NSS_SUCCESS); 1973 1974 /* unmarshall the data */ 1975 if (pbuf->data_off == 0 || pbuf->data_len == 0) 1976 return (NSS_NOTFOUND); 1977 buf = (char *)buffer + pbuf->data_off; 1978 1979 len = pbuf->data_len; 1980 1981 /* marshall data directly into users buffer */ 1982 ret = (*in->str2ent)(buf, len, in->buf.result, in->buf.buffer, 1983 in->buf.buflen); 1984 if (ret == NSS_STR_PARSE_ERANGE) { 1985 in->returnval = 0; 1986 in->returnlen = 0; 1987 in->erange = 1; 1988 } else if (ret == NSS_STR_PARSE_SUCCESS) { 1989 in->returnval = in->buf.result; 1990 in->returnlen = len; 1991 } 1992 in->h_errno = (int)pbuf->p_herrno; 1993 return ((nss_status_t)ret); 1994 } 1995 1996 /* 1997 * Start of _nsc_{search|setent_u|getent_u|endent_u} NSCD interposition funcs 1998 */ 1999 2000 nss_status_t 2001 _nsc_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum, 2002 void *search_args) 2003 { 2004 nss_pheader_t *pbuf; 2005 void *doorptr = NULL; 2006 size_t bufsize = 0; 2007 size_t datasize = 0; 2008 nss_status_t status; 2009 2010 if (_nsc_proc_is_cache() > 0) { 2011 /* internal nscd call - don't use the door */ 2012 return (NSS_TRYLOCAL); 2013 } 2014 2015 /* standard client calls nscd code */ 2016 if (search_args == NULL) 2017 return (NSS_NOTFOUND); 2018 2019 /* get the door buffer & configured size */ 2020 bufsize = ((nss_XbyY_args_t *)search_args)->buf.buflen; 2021 if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0) 2022 return (NSS_TRYLOCAL); 2023 if (doorptr == NULL || bufsize == 0) 2024 return (NSS_TRYLOCAL); 2025 2026 pbuf = (nss_pheader_t *)doorptr; 2027 /* pack argument and request into door buffer */ 2028 pbuf->nsc_callnumber = NSCD_SEARCH; 2029 /* copy relevant door request info into door buffer */ 2030 status = nss_pack((void *)pbuf, bufsize, rootp, 2031 initf, search_fnum, search_args); 2032 2033 /* Packing error return error results */ 2034 if (status != NSS_SUCCESS) 2035 return (status); 2036 2037 /* transfer packed switch request to nscd via door */ 2038 /* data_off can be used because it is header+dbd_len+key_len */ 2039 datasize = pbuf->data_off; 2040 status = _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize); 2041 2042 /* If unsuccessful fallback to standard nss logic */ 2043 if (status != NSS_SUCCESS) { 2044 /* 2045 * check if doors reallocated the memory underneath us 2046 * if they did munmap it or suffer a memory leak 2047 */ 2048 if (doorptr != (void *)pbuf) { 2049 _nsc_resizedoorbuf(bufsize); 2050 munmap((void *)doorptr, bufsize); 2051 } 2052 return (NSS_TRYLOCAL); 2053 } 2054 2055 /* unpack and marshall data/errors to user structure */ 2056 /* set any error conditions */ 2057 status = nss_unpack((void *)doorptr, bufsize, rootp, initf, 2058 search_fnum, search_args); 2059 /* 2060 * check if doors reallocated the memory underneath us 2061 * if they did munmap it or suffer a memory leak 2062 */ 2063 if (doorptr != (void *)pbuf) { 2064 _nsc_resizedoorbuf(bufsize); 2065 munmap((void *)doorptr, bufsize); 2066 } 2067 return (status); 2068 } 2069 2070 /* 2071 * contact nscd for a cookie or to reset an existing cookie 2072 * if nscd fails (NSS_TRYLOCAL) then set cookie to -1 and 2073 * continue diverting to local 2074 */ 2075 nss_status_t 2076 _nsc_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf, 2077 nss_getent_t *contextpp) 2078 { 2079 nss_status_t status = NSS_TRYLOCAL; 2080 struct nss_getent_context *contextp = contextpp->ctx; 2081 nss_pheader_t *pbuf; 2082 void *doorptr = NULL; 2083 size_t bufsize = 0; 2084 size_t datasize = 0; 2085 2086 /* return if already in local mode */ 2087 if (contextp->cookie == NSCD_LOCAL_COOKIE) 2088 return (NSS_TRYLOCAL); 2089 2090 if (_nsc_proc_is_cache() > 0) { 2091 /* internal nscd call - don't try to use the door */ 2092 contextp->cookie = NSCD_LOCAL_COOKIE; 2093 return (NSS_TRYLOCAL); 2094 } 2095 2096 /* get the door buffer & configured size */ 2097 if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0) { 2098 contextp->cookie = NSCD_LOCAL_COOKIE; 2099 return (NSS_TRYLOCAL); 2100 } 2101 if (doorptr == NULL || bufsize == 0) { 2102 contextp->cookie = NSCD_LOCAL_COOKIE; 2103 return (NSS_TRYLOCAL); 2104 } 2105 2106 pbuf = (nss_pheader_t *)doorptr; 2107 pbuf->nsc_callnumber = NSCD_SETENT; 2108 2109 contextp->param.cleanup = NULL; 2110 (*initf)(&contextp->param); 2111 if (contextp->param.name == 0) { 2112 if (contextp->param.cleanup != 0) 2113 (contextp->param.cleanup)(&contextp->param); 2114 errno = ERANGE; /* actually EINVAL */ 2115 return (NSS_ERROR); 2116 } 2117 2118 /* pack relevant setent request info into door buffer */ 2119 status = nss_pack_ent((void *)pbuf, bufsize, rootp, 2120 initf, contextpp); 2121 if (status != NSS_SUCCESS) 2122 return (status); 2123 2124 /* transfer packed switch request to nscd via door */ 2125 /* data_off can be used because it is header+dbd_len+key_len */ 2126 datasize = pbuf->data_off; 2127 status = _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize); 2128 2129 /* If fallback to standard nss logic (door failure) if possible */ 2130 if (status != NSS_SUCCESS) { 2131 if (contextp->cookie == NSCD_NEW_COOKIE) { 2132 contextp->cookie = NSCD_LOCAL_COOKIE; 2133 return (NSS_TRYLOCAL); 2134 } 2135 return (NSS_UNAVAIL); 2136 } 2137 /* unpack returned cookie stash it away */ 2138 status = nss_unpack_ent((void *)doorptr, bufsize, rootp, 2139 initf, contextpp, NULL); 2140 /* save the setent cookie for later use */ 2141 contextp->cookie_setent = contextp->cookie; 2142 /* 2143 * check if doors reallocated the memory underneath us 2144 * if they did munmap it or suffer a memory leak 2145 */ 2146 if (doorptr != (void *)pbuf) { 2147 _nsc_resizedoorbuf(bufsize); 2148 munmap((void *)doorptr, bufsize); 2149 } 2150 return (status); 2151 } 2152 2153 nss_status_t 2154 _nsc_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf, 2155 nss_getent_t *contextpp, void *args) 2156 { 2157 nss_status_t status = NSS_TRYLOCAL; 2158 struct nss_getent_context *contextp = contextpp->ctx; 2159 nss_pheader_t *pbuf; 2160 void *doorptr = NULL; 2161 size_t bufsize = 0; 2162 size_t datasize = 0; 2163 2164 /* return if already in local mode */ 2165 if (contextp->cookie == NSCD_LOCAL_COOKIE) 2166 return (NSS_TRYLOCAL); 2167 2168 /* _nsc_setent_u already checked for nscd local case ... proceed */ 2169 if (args == NULL) 2170 return (NSS_NOTFOUND); 2171 2172 /* get the door buffer & configured size */ 2173 bufsize = ((nss_XbyY_args_t *)args)->buf.buflen; 2174 if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0) 2175 return (NSS_UNAVAIL); 2176 if (doorptr == NULL || bufsize == 0) 2177 return (NSS_UNAVAIL); 2178 2179 pbuf = (nss_pheader_t *)doorptr; 2180 pbuf->nsc_callnumber = NSCD_GETENT; 2181 2182 /* pack relevant setent request info into door buffer */ 2183 status = nss_pack_ent((void *)pbuf, bufsize, rootp, 2184 initf, contextpp); 2185 if (status != NSS_SUCCESS) 2186 return (status); 2187 2188 /* transfer packed switch request to nscd via door */ 2189 /* data_off can be used because it is header+dbd_len+key_len */ 2190 datasize = pbuf->data_off; 2191 status = _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize); 2192 2193 /* If fallback to standard nss logic (door failure) if possible */ 2194 if (status != NSS_SUCCESS) { 2195 if (status == NSS_TRYLOCAL || 2196 contextp->cookie == NSCD_NEW_COOKIE) { 2197 contextp->cookie = NSCD_LOCAL_COOKIE; 2198 2199 /* init the local cookie */ 2200 nss_setent_u(rootp, initf, contextpp); 2201 if (contextpp->ctx == 0) 2202 return (NSS_UNAVAIL); 2203 return (NSS_TRYLOCAL); 2204 } 2205 return (NSS_UNAVAIL); 2206 } 2207 /* check error, unpack and process results */ 2208 status = nss_unpack_ent((void *)doorptr, bufsize, rootp, 2209 initf, contextpp, args); 2210 /* 2211 * check if doors reallocated the memory underneath us 2212 * if they did munmap it or suffer a memory leak 2213 */ 2214 if (doorptr != (void *)pbuf) { 2215 _nsc_resizedoorbuf(bufsize); 2216 munmap((void *)doorptr, bufsize); 2217 } 2218 return (status); 2219 } 2220 2221 nss_status_t 2222 _nsc_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf, 2223 nss_getent_t *contextpp) 2224 { 2225 nss_status_t status = NSS_TRYLOCAL; 2226 struct nss_getent_context *contextp = contextpp->ctx; 2227 nss_pheader_t *pbuf; 2228 void *doorptr = NULL; 2229 size_t bufsize = 0; 2230 size_t datasize = 0; 2231 2232 /* return if already in local mode */ 2233 if (contextp->cookie == NSCD_LOCAL_COOKIE) 2234 return (NSS_TRYLOCAL); 2235 2236 /* _nsc_setent_u already checked for nscd local case ... proceed */ 2237 2238 /* get the door buffer & configured size */ 2239 if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0) 2240 return (NSS_UNAVAIL); 2241 if (doorptr == NULL || bufsize == 0) 2242 return (NSS_UNAVAIL); 2243 2244 /* pack up a NSCD_ENDGET request passing in the cookie */ 2245 pbuf = (nss_pheader_t *)doorptr; 2246 pbuf->nsc_callnumber = NSCD_ENDENT; 2247 2248 /* pack relevant setent request info into door buffer */ 2249 status = nss_pack_ent((void *)pbuf, bufsize, rootp, 2250 initf, contextpp); 2251 if (status != NSS_SUCCESS) 2252 return (status); 2253 2254 /* transfer packed switch request to nscd via door */ 2255 /* data_off can be used because it is header+dbd_len+key_len */ 2256 datasize = pbuf->data_off; 2257 (void) _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize); 2258 2259 /* error codes & unpacking ret values don't matter. We're done */ 2260 2261 /* 2262 * check if doors reallocated the memory underneath us 2263 * if they did munmap it or suffer a memory leak 2264 */ 2265 if (doorptr != (void *)pbuf) { 2266 _nsc_resizedoorbuf(bufsize); 2267 munmap((void *)doorptr, bufsize); 2268 } 2269 2270 /* clean up initf setup */ 2271 if (contextp->param.cleanup != 0) 2272 (contextp->param.cleanup)(&contextp->param); 2273 contextp->param.cleanup = NULL; 2274 2275 /* clear cookie */ 2276 contextp->cookie = NSCD_NEW_COOKIE; 2277 return (NSS_SUCCESS); 2278 } 2279