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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdlib.h> /* getenv() */ 29 #include <assert.h> 30 #include <unistd.h> 31 #include <string.h> 32 #include <dlfcn.h> 33 #include <nss_dbdefs.h> 34 #include <exec_attr.h> 35 #include <gssapi/gssapi.h> 36 #include "nscd_door.h" 37 #include "nscd_switch.h" 38 #include "nscd_log.h" 39 #include "nscd_frontend.h" 40 41 #pragma weak nss_search = _nss_search 42 #define nss_search _nss_search 43 44 extern rwlock_t nscd_smf_service_state_lock; 45 46 /* nscd id: main, forker, or child */ 47 extern int _whoami; 48 49 static int 50 retry_test(nss_status_t res, int n, struct __nsw_lookup_v1 *lkp) 51 { 52 if (res != NSS_TRYAGAIN && res != NSS_NISSERVDNS_TRYAGAIN) { 53 if (res == NSS_SUCCESS) { 54 __NSW_UNPAUSE_ACTION(lkp->actions[__NSW_TRYAGAIN]); 55 __NSW_UNPAUSE_ACTION( 56 lkp->actions[__NSW_NISSERVDNS_TRYAGAIN]); 57 } 58 return (0); 59 } 60 61 if ((res == NSS_TRYAGAIN && 62 lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER) || 63 (res == NSS_NISSERVDNS_TRYAGAIN && 64 lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER)) 65 return (1); 66 67 if (res == NSS_TRYAGAIN && 68 lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES) 69 if (n <= lkp->max_retries) 70 return (1); 71 else { 72 lkp->actions[__NSW_TRYAGAIN] = __NSW_TRYAGAIN_PAUSED; 73 return (0); 74 } 75 76 if (res == NSS_NISSERVDNS_TRYAGAIN && 77 lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES) 78 if (n <= lkp->max_retries) 79 return (1); 80 else { 81 lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] = 82 __NSW_TRYAGAIN_PAUSED; 83 return (0); 84 } 85 86 return (0); 87 } 88 89 static thread_key_t loopback_key; 90 static mutex_t loopback_key_lock = DEFAULTMUTEX; 91 static int loopback_key_created = 0; 92 typedef struct lb_key { 93 int srci; 94 int dbi; 95 int fnum; 96 int *lb_flagp; 97 } lb_key_t; 98 99 static int 100 set_loopback_key(lb_key_t *key) { 101 102 int rc = 0; 103 lb_key_t *k; 104 105 if (!loopback_key_created) { 106 (void) mutex_lock(&loopback_key_lock); 107 if (!loopback_key_created) { 108 if ((rc = thr_keycreate(&loopback_key, 109 NULL)) == 0) 110 loopback_key_created = 1; 111 } 112 (void) mutex_unlock(&loopback_key_lock); 113 } 114 if (rc == 0) { 115 /* set key if not already set */ 116 if (thr_getspecific(loopback_key, (void **)&k) == 0 && 117 k == NULL) { 118 rc = thr_setspecific(loopback_key, key); 119 } 120 } 121 122 return (rc); 123 } 124 125 static lb_key_t * 126 get_loopback_key(void) { 127 128 char *me = "get_loopback_key"; 129 int rc = 0; 130 lb_key_t *k = NULL; 131 132 if (!loopback_key_created) 133 return (NULL); 134 135 rc = thr_getspecific(loopback_key, (void **)&k); 136 137 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 138 (me, "get loopback key rc= %d, key = %p\n", rc, k); 139 140 if (rc == 0 && k != NULL) 141 return (k); 142 143 return (NULL); 144 } 145 146 static void 147 clear_loopback_key(lb_key_t *key) { 148 149 char *me = "clear_loopback_key"; 150 151 if (loopback_key_created && key != 0) { 152 /* 153 * key->lb_flagp points to the location of the 154 * flag, check_flag, in the stack where it was 155 * first set; clearing the flag tells that 156 * stack the loopback error has been resolved 157 */ 158 *key->lb_flagp = 0; 159 (void) thr_setspecific(loopback_key, NULL); 160 } 161 162 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 163 (me, "key %p cleared\n", key); 164 } 165 166 static thread_key_t initf_key; 167 static mutex_t initf_key_lock = DEFAULTMUTEX; 168 static int initf_key_created = 0; 169 170 static int 171 set_initf_key(void *pbuf) { 172 173 int rc = 0; 174 175 if (!initf_key_created) { 176 (void) mutex_lock(&initf_key_lock); 177 if (!initf_key_created) { 178 if ((rc = thr_keycreate(&initf_key, NULL)) == 0) 179 initf_key_created = 1; 180 } 181 (void) mutex_unlock(&initf_key_lock); 182 } 183 if (rc == 0) 184 rc = thr_setspecific(initf_key, pbuf); 185 186 return (rc); 187 } 188 189 static void * 190 get_initf_key(void) { 191 192 char *me = "get_initf_key"; 193 void *pbuf; 194 int rc = 0; 195 196 if (!initf_key_created) 197 return (NULL); 198 199 rc = thr_getspecific(initf_key, (void **)&pbuf); 200 201 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 202 (me, "got initf pbuf rc= %d, key = %p\n", rc, pbuf); 203 204 if (rc == 0 && pbuf != NULL) 205 return (pbuf); 206 207 return (NULL); 208 } 209 210 static void 211 clear_initf_key(void) { 212 213 char *me = "clear_initf_key"; 214 215 if (initf_key_created) 216 (void) thr_setspecific(initf_key, NULL); 217 218 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 219 (me, "initf pbuf cleared\n"); 220 } 221 222 /* 223 * Call the input initf function to extract the 224 * NSS front end parameters and examine them to 225 * determine if an NSS lookup is to be performed 226 * on a regular or a pseudo (called from compat 227 * backend) database. Then set the necessary 228 * parameters for later data structures creation 229 * and processing. 230 */ 231 static nscd_rc_t 232 getparams( 233 int search_fnum, 234 nss_db_initf_t initf, 235 nscd_nsw_params_t *params) 236 { 237 238 nscd_rc_t rc = NSCD_SUCCESS; 239 nss_db_params_t *p; 240 int j; 241 char *dbn; 242 const char *n; 243 244 p = ¶ms->p; 245 (void) memset(p, 0, sizeof (*p)); 246 (*initf)(p); 247 params->dbi = -1; 248 params->cfgdbi = -1; 249 params->compati = -1; 250 params->dnsi = -1; 251 252 /* map database name to index */ 253 n = p->name; 254 for (j = 0; j < NSCD_NUM_DB; j++) { 255 dbn = NSCD_NSW_DB_NAME(j); 256 if (*n != *dbn) 257 continue; 258 if (strcmp(n, dbn) == 0) { 259 params->dbi = j; 260 if (*n != 'h' && *n != 'i' && *n != 's' && *n != 'a') 261 break; 262 if (strcmp(n, NSS_DBNAM_HOSTS) == 0 && 263 search_fnum == NSS_DBOP_HOSTS_BYNAME) 264 params->dnsi = 0; 265 else if (strcmp(n, NSS_DBNAM_IPNODES) == 0 && 266 search_fnum == NSS_DBOP_IPNODES_BYNAME) 267 params->dnsi = 1; 268 else if (strcmp(n, NSS_DBNAM_SHADOW) == 0) 269 params->privdb = 1; 270 else if (strcmp(n, NSS_DBNAM_AUDITUSER) == 0) 271 params->privdb = 1; 272 break; 273 } 274 } 275 276 /* 277 * use the switch policy for passwd_compat or 278 * group_compat? 279 */ 280 if (p->config_name != NULL) { 281 282 n = p->config_name; 283 for (j = 0; j < NSCD_NUM_DB; j++) { 284 dbn = NSCD_NSW_DB_NAME(j); 285 if (*n == *dbn) { 286 if (strcmp(n, dbn) == 0) { 287 params->cfgdbi = j; 288 break; 289 } 290 } 291 } 292 } 293 294 /* map the database name to the pseudo database index */ 295 if (params->cfgdbi != -1) { 296 if (strstr(p->config_name, "_compat") != NULL) { 297 n = p->name; 298 for (j = params->cfgdbi; j < NSCD_NUM_DB; j++) { 299 dbn = NSCD_NSW_DB_NAME(j); 300 if (*n == *dbn) { 301 if (strcmp(n, dbn) == 0) { 302 params->compati = j; 303 break; 304 } 305 } 306 } 307 } 308 } 309 310 assert(params->dbi != -1); 311 return (rc); 312 } 313 314 static void 315 nscd_initf(nss_db_params_t *p) 316 { 317 nss_pheader_t *pbuf; 318 nssuint_t off; 319 nss_dbd_t *pdbd; 320 char *me = "nscd_initf"; 321 322 pbuf = (nss_pheader_t *)get_initf_key(); 323 if (pbuf == NULL) { 324 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 325 (me, "ERROR: initf key not set\n"); 326 return; 327 } 328 329 if (pbuf->dbd_len <= sizeof (nss_dbd_t)) { 330 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 331 (me, "invalid db front params data ? dbd_len = %d\n", 332 pbuf->dbd_len); 333 return; 334 } 335 336 off = pbuf->dbd_off; 337 pdbd = (nss_dbd_t *)((void *)((char *)pbuf + off)); 338 339 p->name = (char *)pdbd + pdbd->o_name; 340 p->config_name = (char *)pdbd + pdbd->o_config_name; 341 p->default_config = (char *)pdbd + pdbd->o_default_config; 342 p->flags = (enum nss_dbp_flags)pdbd->flags; 343 (void) memcpy(&p->private, &pbuf->nscdpriv, sizeof (p->private)); 344 345 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 346 (me, "db frontend params: name =%s, config_name = %s, " 347 "default_config = %s, flags = %x\n", p->name, 348 (p->config_name && *p->config_name != '\0' ? 349 p->config_name : "<NOT SPECIFIED>"), 350 (p->default_config && *p->default_config != '\0' ? 351 p->default_config : "<NOT SPECIFIED>"), 352 p->flags); 353 } 354 355 356 static void 357 trace_result( 358 int dbi, 359 int srci, 360 int op, 361 nss_status_t res, 362 nss_XbyY_args_t *arg) 363 { 364 char *res_str; 365 char *src = "?"; 366 char *db = "?"; 367 char *me = "nss_search"; 368 369 switch (res) { 370 case NSS_SUCCESS: 371 res_str = "NSS_SUCCESS"; 372 break; 373 case NSS_NOTFOUND: 374 res_str = "NSS_NOTFOUND"; 375 break; 376 case NSS_UNAVAIL: 377 res_str = "NSS_UNAVAIL"; 378 break; 379 case NSS_TRYAGAIN: 380 res_str = "NSS_TRYAGAIN"; 381 break; 382 case NSS_NISSERVDNS_TRYAGAIN: 383 res_str = "NSS_NISSERVDNS_TRYAGAIN"; 384 break; 385 default: 386 res_str = "UNKNOWN STATUS"; 387 break; 388 } 389 390 if (dbi != -1) 391 db = NSCD_NSW_DB_NAME(dbi); 392 if (srci != -1) 393 src = NSCD_NSW_SRC_NAME(srci); 394 395 if (res == NSS_SUCCESS) { 396 _nscd_logit(me, 397 "%s: database: %s, operation: %d, source: %s returned \"%s\", length = %d\n", 398 res_str, db, op, src, arg->buf.buffer, arg->returnlen); 399 400 return; 401 } 402 403 _nscd_logit(me, 404 "%s: database: %s, operation: %d, source: %s, erange= %d, errno: %s \n", 405 res_str, db, op, src, arg->erange, strerror(arg->h_errno)); 406 } 407 408 /* 409 * Determine if a request should be done locally in the getXbyY caller's 410 * process. Return none zero if yes, 0 otherwise. 411 * This function returnis 1 if: 412 * -- the database is exec_attr and the search_flag is GET_ALL 413 */ 414 static int 415 try_local( 416 int dbi, 417 void *arg) 418 { 419 struct nss_XbyY_args *ap = (struct nss_XbyY_args *)arg; 420 _priv_execattr *ep; 421 int rc = 0; 422 char *me = "try_local"; 423 424 if (strcmp(NSCD_NSW_DB_NAME(dbi), NSS_DBNAM_EXECATTR) == 0) { 425 if ((ep = ap->key.attrp) != NULL && 426 ep->search_flag == GET_ALL) 427 rc = 1; 428 } 429 430 if (rc != 0) { 431 432 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 433 (me, "TRYLOCAL: exec_attr:GET_ALL\n"); 434 } 435 436 return (rc); 437 } 438 439 static nscd_rc_t 440 get_dns_funcs(int dnsi, void **func_p) 441 { 442 char *me = "get_dns_funcs"; 443 static void *handle = NULL; 444 static mutex_t func_lock = DEFAULTMUTEX; 445 void *sym; 446 char *func_name[2] = { "_nss_get_dns_hosts_name", 447 "_nss_get_dns_ipnodes_name" }; 448 static void *func[2] = {NULL, NULL}; 449 450 if (handle != NULL && dnsi > 0 && func[dnsi] != NULL) { 451 (void) memcpy(func_p, &func[dnsi], sizeof (void *)); 452 return (NSCD_SUCCESS); 453 } 454 455 (void) mutex_lock(&func_lock); 456 457 /* close the handle if requested */ 458 if (dnsi < 0) { 459 if (handle != NULL) { 460 (void) dlclose(handle); 461 func[0] = NULL; 462 func[1] = NULL; 463 } 464 (void) mutex_unlock(&func_lock); 465 return (NSCD_SUCCESS); 466 } 467 468 if (handle != NULL && func[dnsi] != NULL) { 469 (void) memcpy(func_p, &func[dnsi], sizeof (void *)); 470 (void) mutex_unlock(&func_lock); 471 return (NSCD_SUCCESS); 472 } 473 474 if (handle == NULL) { 475 handle = dlopen("nss_dns.so.1", RTLD_LAZY); 476 if (handle == NULL) { 477 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 478 NSCD_LOG_LEVEL_ERROR) 479 (me, "unable to dlopen nss_dns.so.1\n"); 480 (void) mutex_unlock(&func_lock); 481 return (NSCD_CFG_DLOPEN_ERROR); 482 } 483 } 484 485 if ((sym = dlsym(handle, func_name[dnsi])) == NULL) { 486 487 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_ERROR) 488 (me, "unable to find symbol %s\n", func_name[dnsi]); 489 (void) mutex_unlock(&func_lock); 490 return (NSCD_CFG_DLSYM_ERROR); 491 } else { 492 (void) memcpy(func_p, &sym, sizeof (void *)); 493 (void) memcpy(&func[dnsi], &sym, sizeof (void *)); 494 } 495 496 (void) mutex_unlock(&func_lock); 497 return (NSCD_SUCCESS); 498 } 499 500 static nss_status_t 501 search_dns_withttl(nscd_sw_return_t *swret, char *srcname, int dnsi) 502 { 503 nss_status_t (*func)(); 504 nss_status_t res = NSS_UNAVAIL; 505 nscd_rc_t rc; 506 507 swret->noarg = 0; 508 if (strcmp(srcname, "dns") != 0) 509 return (NSS_ERROR); 510 511 rc = get_dns_funcs(dnsi, (void **)&func); 512 if (rc == NSCD_SUCCESS) 513 res = (func)(NULL, &swret->pbuf, &swret->pbufsiz); 514 return (res); 515 } 516 517 /* 518 * Returns a flag to indicate if needs to fall back to the 519 * main nscd when a per-user lookup failed with rc NSS_NOTFOUND. 520 */ 521 static int 522 set_fallback_flag(char *srcname, nss_status_t rc) 523 { 524 char *me = "set_fallback_flag"; 525 if (strcmp(srcname, "ldap") == 0 && rc == NSS_NOTFOUND) { 526 527 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 528 (me, "NSS_NOTFOUND (ldap): fallback to main nscd " 529 "may be needed\n"); 530 return (1); 531 } 532 return (0); 533 } 534 535 nss_status_t 536 nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum, 537 void *search_args) 538 { 539 char *me = "nss_search"; 540 nss_status_t res = NSS_UNAVAIL; 541 nscd_nsw_state_t *s = NULL; 542 int n_src; 543 unsigned int status_vec = 0; 544 int dbi, srci = -1; 545 int check_loopback = 0; 546 int state_thr = 0; 547 lb_key_t key, *k = NULL; 548 nss_db_root_t root_db; 549 nscd_nsw_params_t params; 550 nscd_sw_return_t *swret; 551 552 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 553 (me, "rootp = %p, initf = %p, search_fnum = %d, " 554 "search_args = %p\n", rootp, initf, 555 search_fnum, search_args); 556 557 NSCD_SW_STATS_G.lookup_request_received_g++; 558 NSCD_SW_STATS_G.lookup_request_in_progress_g++; 559 NSCD_SW_STATS_G.lookup_request_queued_g++; 560 561 /* determine db index, cfg db index, etc */ 562 (void) getparams(search_fnum, initf, ¶ms); 563 dbi = params.dbi; 564 565 /* get address of the switch engine return data area */ 566 if (initf == nscd_initf) { 567 swret = (nscd_sw_return_t *)params.p.private; 568 swret->srci = -1; 569 } else { 570 swret = NULL; 571 params.dnsi = -1; 572 } 573 574 /* 575 * for request that should be processed by the client, 576 * send it back with status NSS_TRYLOCAL 577 */ 578 if (try_local(dbi, search_args) == 1) { 579 res = NSS_TRYLOCAL; 580 goto error_exit; 581 } 582 583 NSCD_SW_STATS(dbi).lookup_request_received++; 584 NSCD_SW_STATS(dbi).lookup_request_in_progress++; 585 NSCD_SW_STATS(dbi).lookup_request_queued++; 586 587 /* if lookup not enabled, return NSS_UNAVAIL */ 588 if (!(NSCD_SW_CFG_G.enable_lookup_g == nscd_true && 589 NSCD_SW_CFG(dbi).enable_lookup == nscd_true)) { 590 591 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 592 (me, "lookup not enabled for %s\n", NSCD_NSW_DB_NAME(dbi)); 593 594 goto error_exit; 595 } 596 597 /* determine if loopback checking is configured */ 598 if (NSCD_SW_CFG_G.enable_loopback_checking_g == nscd_true && 599 NSCD_SW_CFG(dbi).enable_loopback_checking == nscd_true) { 600 check_loopback = 1; 601 602 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 603 (me, "loopback checking enabled for %s\n", 604 NSCD_NSW_DB_NAME(dbi)); 605 } 606 607 if (check_loopback) { 608 k = get_loopback_key(); 609 if (k != NULL) { 610 if (k->dbi != dbi || k->fnum != search_fnum) { 611 clear_loopback_key(k); 612 k = NULL; 613 } 614 } 615 } 616 617 if (s == 0) { 618 nscd_rc_t rc; 619 620 if (check_loopback) { 621 rc = _nscd_get_nsw_state_thread(&root_db, ¶ms); 622 state_thr = 1; 623 } else 624 rc = _nscd_get_nsw_state(&root_db, ¶ms); 625 626 NSCD_SW_STATS_G.lookup_request_queued_g--; 627 NSCD_SW_STATS(dbi).lookup_request_queued--; 628 629 if (rc != NSCD_SUCCESS) 630 goto error_exit; 631 632 s = (nscd_nsw_state_t *)root_db.s; 633 } 634 635 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 636 (me, "database = %s, config = [ %s ]\n", NSCD_NSW_DB_NAME(dbi), 637 (*s->nsw_cfg_p)->nsw_cfg_str); 638 639 for (n_src = 0; n_src < s->max_src; n_src++) { 640 nss_backend_t *be; 641 nss_backend_op_t funcp; 642 struct __nsw_lookup_v1 *lkp; 643 int smf_state; 644 int n_loop = 0; 645 int max_retry = 10; 646 647 res = NSS_UNAVAIL; 648 649 if (n_src == 0) 650 lkp = s->config->lookups; 651 else 652 lkp = lkp->next; 653 654 /* set the number of max. retries */ 655 if (lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES) 656 max_retry = lkp->max_retries; 657 658 srci = (*s->nsw_cfg_p)->src_idx[n_src]; 659 if (swret != NULL) 660 swret->srci = srci; 661 662 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 663 (me, "nsw source = %s\n", NSCD_NSW_SRC_NAME(srci)); 664 665 /* if no privilege to look up, skip */ 666 if (params.privdb == 1 && swret != NULL && 667 strcmp(NSCD_NSW_SRC_NAME(srci), "files") == 0 && 668 _nscd_get_client_euid() != 0) { 669 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 670 NSCD_LOG_LEVEL_DEBUG) 671 (me, "no privilege to look up, skip source\n"); 672 673 goto next_src; 674 } 675 676 /* get state of the (backend) client service */ 677 smf_state = _nscd_get_smf_state(srci, dbi, 0); 678 679 /* stop if the source is one that should be TRYLOCAL */ 680 if (smf_state == NSCD_SVC_STATE_UNKNOWN_SRC) { 681 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 682 NSCD_LOG_LEVEL_DEBUG) 683 (me, "returning TRYLOCAL ... \n"); 684 res = NSS_TRYLOCAL; 685 goto free_nsw_state; 686 } 687 688 if (check_loopback && k != NULL) { 689 690 if (k->srci == srci && k->dbi == dbi) 691 if (k->fnum == search_fnum) { 692 693 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 694 NSCD_LOG_LEVEL_DEBUG) 695 (me, "loopback detected: " 696 "source = %s, database = %s " 697 "search fnum = %d\n", 698 NSCD_NSW_SRC_NAME(srci), 699 NSCD_NSW_DB_NAME(dbi), search_fnum); 700 701 NSCD_SW_STATS_G.loopback_nsw_db_skipped_g++; 702 NSCD_SW_STATS(dbi).loopback_nsw_db_skipped++; 703 continue; 704 } 705 } 706 707 be = s->be[n_src]; 708 if (be != NULL) 709 funcp = NSS_LOOKUP_DBOP(be, search_fnum); 710 711 if ((params.dnsi >= 0 && be == 0) || (params.dnsi < 0 && 712 (be == 0 || (smf_state != NSCD_SVC_STATE_UNINITED && 713 smf_state < SCF_STATE_ONLINE) || funcp == 0))) { 714 715 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 716 NSCD_LOG_LEVEL_DEBUG) 717 (me, "unable to look up source %s: be = %p, " 718 "smf state = %d, funcp = %p\n", 719 NSCD_NSW_SRC_NAME(srci), be, smf_state, funcp); 720 721 goto next_src; 722 } 723 724 do { 725 /* 726 * we can only retry max_retry times, 727 * otherwise threads may get stuck in this 728 * do-while loop forever 729 */ 730 if (n_loop > max_retry) { 731 if (swret != NULL) 732 res = NSS_TRYLOCAL; 733 goto free_nsw_state; 734 } 735 736 /* 737 * set up to prevent loopback 738 */ 739 if (check_loopback && k == NULL) { 740 key.srci = srci; 741 key.dbi = dbi; 742 key.fnum = search_fnum; 743 key.lb_flagp = &check_loopback; 744 (void) set_loopback_key(&key); 745 k = &key; 746 } 747 748 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 749 NSCD_LOG_LEVEL_DEBUG) 750 (me, "looking up source = %s, loop# = %d \n", 751 NSCD_NSW_SRC_NAME(srci), n_loop); 752 753 /* 754 * search the backend, if hosts lookups, 755 * try to get the hosts data with ttl first 756 */ 757 if (params.dnsi >= 0) { 758 res = search_dns_withttl(swret, 759 NSCD_NSW_SRC_NAME(srci), 760 params.dnsi); 761 /* 762 * if not able to get ttl, fall back 763 * to the regular backend call 764 */ 765 if (res == NSS_ERROR) 766 res = (*funcp)(be, search_args); 767 else { 768 /* 769 * status/result are in the 770 * packed buffer, not 771 * search_args 772 */ 773 swret->noarg = 1; 774 } 775 } else 776 res = (*funcp)(be, search_args); 777 if (swret != NULL) 778 swret->errnum = errno; 779 780 /* 781 * backend is not up, check and update the 782 * smf state table 783 */ 784 if (res == NSS_UNAVAIL) 785 (void) _nscd_get_smf_state(srci, dbi, 1); 786 787 /* 788 * may need to fall back to use the main nscd 789 * if per-user lookup 790 */ 791 if (_whoami == NSCD_CHILD && swret != NULL) 792 swret->fallback = set_fallback_flag( 793 NSCD_NSW_SRC_NAME(srci), res); 794 795 _NSCD_LOG_IF(NSCD_LOG_SWITCH_ENGINE, 796 NSCD_LOG_LEVEL_DEBUG) { 797 798 /* 799 * set up to trace the result/status 800 * of the dns/ttl lookup 801 */ 802 if (swret != NULL && swret->noarg == 1) { 803 nss_pheader_t *phdr; 804 struct nss_XbyY_args *arg; 805 arg = (struct nss_XbyY_args *) 806 search_args; 807 phdr = (nss_pheader_t *)swret->pbuf; 808 arg->buf.buffer = (char *)phdr + 809 phdr->data_off; 810 arg->returnlen = phdr->data_len; 811 if (phdr->p_errno == ERANGE) 812 arg->erange = 1; 813 arg->h_errno = phdr->p_herrno; 814 } 815 816 trace_result(dbi, srci, search_fnum, res, 817 (nss_XbyY_args_t *)search_args); 818 } 819 820 n_loop++; 821 } while (retry_test(res, n_loop, lkp)); 822 823 next_src: 824 825 status_vec |= (1 << res); 826 827 if (__NSW_ACTION_V1(lkp, res) == __NSW_RETURN) { 828 break; 829 } 830 } 831 832 free_nsw_state: 833 834 if (state_thr == 1) 835 _nscd_put_nsw_state_thread(s); 836 else 837 _nscd_put_nsw_state(s); 838 if (check_loopback && k != NULL) 839 clear_loopback_key(k); 840 841 if (res != NSS_SUCCESS) 842 goto error_exit; 843 844 NSCD_SW_STATS_G.lookup_request_succeeded_g++; 845 NSCD_SW_STATS(dbi).lookup_request_succeeded++; 846 NSCD_SW_STATS_G.lookup_request_in_progress_g--; 847 NSCD_SW_STATS(dbi).lookup_request_in_progress--; 848 849 return (NSS_SUCCESS); 850 851 error_exit: 852 853 NSCD_SW_STATS_G.lookup_request_failed_g++; 854 NSCD_SW_STATS_G.lookup_request_in_progress_g--; 855 NSCD_SW_STATS(dbi).lookup_request_failed++; 856 NSCD_SW_STATS(dbi).lookup_request_in_progress--; 857 858 return (res); 859 } 860 861 862 /* ===> get/set/endent */ 863 864 static void nss_setent_u(nss_db_root_t *, 865 nss_db_initf_t, 866 nss_getent_t *); 867 static nss_status_t nss_getent_u(nss_db_root_t *, 868 nss_db_initf_t, 869 nss_getent_t *, 870 void *); 871 static void nss_endent_u(nss_db_root_t *, 872 nss_db_initf_t, 873 nss_getent_t *); 874 875 void 876 nss_setent(nss_db_root_t *rootp, nss_db_initf_t initf, 877 nss_getent_t *contextpp) 878 { 879 if (contextpp == 0) 880 return; 881 nss_setent_u(rootp, initf, contextpp); 882 } 883 884 nss_status_t 885 nss_getent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp, 886 void *args) 887 { 888 nss_status_t status; 889 890 if (contextpp == 0) { 891 return (NSS_UNAVAIL); 892 } 893 status = nss_getent_u(rootp, initf, contextpp, args); 894 return (status); 895 } 896 897 void 898 nss_endent(nss_db_root_t *rootp, nss_db_initf_t initf, 899 nss_getent_t *contextpp) 900 { 901 if (contextpp == 0) 902 return; 903 nss_endent_u(rootp, initf, contextpp); 904 } 905 906 /*ARGSUSED*/ 907 static void 908 end_iter_u(nss_db_root_t *rootp, struct nss_getent_context *contextp) 909 { 910 nscd_getent_context_t *ctx; 911 nscd_nsw_state_t *s; 912 nss_backend_t *be; 913 int n_src; 914 915 ctx = (nscd_getent_context_t *)contextp; 916 s = ctx->nsw_state; 917 n_src = ctx->n_src; 918 be = ctx->be; 919 920 if (s != 0) { 921 if (n_src < s->max_src && be != 0) { 922 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0); 923 ctx->be = 0; /* Should be unnecessary, but hey */ 924 } 925 } 926 ctx->n_src = 0; 927 } 928 929 static void 930 nss_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf, 931 nss_getent_t *contextpp) 932 { 933 char *me = "nss_setent_u"; 934 nscd_nsw_state_t *s; 935 nscd_getent_context_t *contextp; 936 nscd_nsw_params_t params; 937 nss_db_root_t root; 938 nss_backend_t *be; 939 int n_src, i; 940 nscd_sw_return_t *swret = NULL; 941 942 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 943 (me, "rootp = %p, initf = %p, contextpp = %p \n", 944 rootp, initf, contextpp); 945 946 /* get the nsw db index via the initf function */ 947 (void) getparams(-1, initf, ¶ms); 948 949 /* get address of the switch engine return data area */ 950 if (initf == nscd_initf) 951 swret = (nscd_sw_return_t *)params.p.private; 952 953 /* if no privilege to look up, return */ 954 if (params.privdb == 1 && swret != NULL && 955 ((nss_pheader_t *)(swret->pbuf))->p_euid != 0) { 956 957 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 958 (me, "no privilege \n"); 959 return; 960 } 961 962 if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) { 963 if ((_nscd_get_getent_ctx(contextpp, ¶ms)) != 964 NSCD_SUCCESS) { 965 return; 966 } 967 contextp = (nscd_getent_context_t *)contextpp->ctx; 968 } 969 s = contextp->nsw_state; 970 971 if (s == 0) { 972 if (_nscd_get_nsw_state(&root, ¶ms) != 973 NSCD_SUCCESS) { 974 return; 975 } 976 s = (nscd_nsw_state_t *)root.s; 977 contextp->nsw_state = s; 978 979 } else { 980 s = contextp->nsw_state; 981 n_src = contextp->n_src; 982 be = contextp->be; 983 if (n_src == 0 && be != 0) { 984 /* 985 * Optimization: don't do endent, don't change 986 * backends, just do the setent. Look Ma, no locks 987 * (nor any context that needs updating). 988 */ 989 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0); 990 return; 991 } 992 if (n_src < s->max_src && be != 0) { 993 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0); 994 contextp->be = 0; /* Play it safe */ 995 } 996 } 997 for (n_src = 0, be = 0; n_src < s->max_src && 998 (be = s->be[n_src]) == 0; n_src++) { 999 ; 1000 } 1001 1002 contextp->n_src = n_src; 1003 contextp->be = be; 1004 1005 if (be == 0) { 1006 /* Things are broken enough that we can't do setent/getent */ 1007 nss_endent_u(rootp, initf, contextpp); 1008 return; 1009 } 1010 1011 /* 1012 * make sure all the backends are supported 1013 */ 1014 for (i = 0; i < s->max_src; i++) { 1015 int st, srci; 1016 1017 srci = (*s->nsw_cfg_p)->src_idx[i]; 1018 st = _nscd_get_smf_state(srci, params.dbi, 1); 1019 if (st == NSCD_SVC_STATE_UNKNOWN_SRC || 1020 st == NSCD_SVC_STATE_UNINITED) { 1021 nss_endent_u(rootp, initf, contextpp); 1022 1023 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 1024 NSCD_LOG_LEVEL_DEBUG) 1025 (me, "backend (%s) not available (state = %d)\n", 1026 NSCD_NSW_SRC_NAME(srci), st); 1027 1028 return; 1029 } 1030 } 1031 1032 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0); 1033 } 1034 1035 nss_status_t 1036 nss_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf, 1037 nss_getent_t *contextpp, void *args) 1038 { 1039 char *me = "nss_getent_u"; 1040 nscd_nsw_state_t *s; 1041 nscd_getent_context_t *contextp; 1042 int n_src; 1043 nss_backend_t *be; 1044 1045 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1046 (me, "rootp = %p, initf = %p, contextpp = %p, args = %p\n", 1047 rootp, initf, contextpp, args); 1048 1049 if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) { 1050 nss_setent_u(rootp, initf, contextpp); 1051 if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) { 1052 /* Give up */ 1053 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 1054 NSCD_LOG_LEVEL_ERROR) 1055 (me, "not able to obtain getent context ... give up\n"); 1056 1057 return (NSS_UNAVAIL); 1058 } 1059 } 1060 1061 s = contextp->nsw_state; 1062 n_src = contextp->n_src; 1063 be = contextp->be; 1064 1065 if (s == 0) { 1066 /* 1067 * We've done an end_iter() and haven't done nss_setent() 1068 * or nss_endent() since; we should stick in this state 1069 * until the caller invokes one of those two routines. 1070 */ 1071 return (NSS_SUCCESS); 1072 } 1073 1074 while (n_src < s->max_src) { 1075 nss_status_t res; 1076 struct __nsw_lookup_v1 *lkp = NULL; 1077 int n; 1078 1079 /* get the nsw config for the current source */ 1080 lkp = s->config->lookups; 1081 for (n = 0; n < n_src; n++) 1082 lkp = lkp->next; 1083 1084 if (be == 0) { 1085 /* If it's null it's a bug, but let's play safe */ 1086 res = NSS_UNAVAIL; 1087 } else { 1088 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 1089 NSCD_LOG_LEVEL_DEBUG) 1090 (me, "database: %s, backend: %s, nsswitch config: %s\n", 1091 NSCD_NSW_DB_NAME(s->dbi), 1092 lkp->service_name, 1093 (*s->nsw_cfg_p)->nsw_cfg_str); 1094 1095 res = NSS_INVOKE_DBOP(be, NSS_DBOP_GETENT, args); 1096 } 1097 1098 if (__NSW_ACTION_V1(lkp, res) == __NSW_RETURN) { 1099 if (res != __NSW_SUCCESS) { 1100 end_iter_u(rootp, 1101 (struct nss_getent_context *)contextp); 1102 } 1103 return (res); 1104 } 1105 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0); 1106 do { 1107 n_src++; 1108 } while (n_src < s->max_src && 1109 (be = s->be[n_src]) == 0); 1110 if (be == 0) { 1111 /* 1112 * This is the case where we failed to get the backend 1113 * for the last source. We exhausted all sources. 1114 */ 1115 nss_endent_u(rootp, initf, contextpp); 1116 return (NSS_SUCCESS); 1117 } 1118 contextp->n_src = n_src; 1119 contextp->be = be; 1120 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0); 1121 } 1122 /* Got to the end of the sources without finding another entry */ 1123 end_iter_u(rootp, (struct nss_getent_context *)contextp); 1124 return (NSS_SUCCESS); 1125 /* success is either a successful entry or end of the sources */ 1126 } 1127 1128 /*ARGSUSED*/ 1129 void 1130 nss_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf, 1131 nss_getent_t *contextpp) 1132 { 1133 char *me = "nss_endent_u"; 1134 nscd_getent_context_t *contextp; 1135 1136 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1137 (me, "rootp = %p, initf = %p, contextpp = %p \n", 1138 rootp, initf, contextpp); 1139 1140 if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) { 1141 /* nss_endent() on an unused context is a no-op */ 1142 return; 1143 } 1144 end_iter_u(rootp, (struct nss_getent_context *)contextp); 1145 _nscd_put_getent_ctx(contextp); 1146 contextpp->ctx = NULL; 1147 } 1148 1149 /* 1150 * _nss_db_state_destr() and nss_delete() do nothing in nscd 1151 * but is needed to make the caller (below nscd) happy 1152 */ 1153 /*ARGSUSED*/ 1154 void 1155 _nss_db_state_destr(struct nss_db_state *s) 1156 { 1157 /* nsw state in nscd is always reused, so do nothing here */ 1158 } 1159 1160 /*ARGSUSED*/ 1161 void 1162 nss_delete(nss_db_root_t *rootp) 1163 { 1164 /* 1165 * the only resource kept tracked by the nss_db_root_t 1166 * is the nsw state which is always reused and no need 1167 * to be freed. So just return. 1168 */ 1169 } 1170 1171 /* 1172 * Start of nss_psearch/nss_psetent()/nss_pgetent()/nss_pendent() 1173 * buffers switch entry points 1174 */ 1175 1176 /* 1177 * nss_psearch opens a packed structure header, assembles a local 1178 * nss_XbyY_args_t structure and calls the local copy of nss_search. 1179 * The return data is assembled in "files native format" in the 1180 * return buffer location. Status if packed back up with the buffer 1181 * and the whole wad is returned to the cache or the client. 1182 */ 1183 1184 void 1185 nss_psearch(void *buffer, size_t length) 1186 { 1187 /* inputs */ 1188 nss_db_initf_t initf; 1189 int dbop; 1190 int rc; 1191 nss_XbyY_args_t arg; 1192 nss_status_t status; 1193 nscd_sw_return_t swret = { 0 }, *swrp = &swret; 1194 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1195 char *me = "nss_psearch"; 1196 1197 if (buffer == NULL || length == 0) { 1198 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1199 } 1200 1201 status = nss_packed_arg_init(buffer, length, 1202 NULL, &initf, &dbop, &arg); 1203 if (status != NSS_SUCCESS) { 1204 NSCD_RETURN_STATUS(pbuf, status, -1); 1205 } 1206 1207 /* 1208 * pass the address of the return data area 1209 * for the switch engine to return its own data 1210 */ 1211 (void) memcpy(&pbuf->nscdpriv, &swrp, sizeof (swrp)); 1212 swret.pbuf = buffer; 1213 swret.pbufsiz = length; 1214 1215 /* 1216 * use the generic nscd_initf for all database lookups 1217 * (the TSD key is the pointer to the packed header) 1218 */ 1219 rc = set_initf_key(pbuf); 1220 if (rc != 0) { 1221 NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL); 1222 } 1223 initf = nscd_initf; 1224 1225 /* Perform local search and pack results into return buffer */ 1226 /* nscd's search ignores db_root */ 1227 status = nss_search(NULL, initf, dbop, &arg); 1228 1229 /* 1230 * If status is NSS_NOTFOUND and ldap also returned 1231 * NSS_NOTFOUND, it is possible that the user does 1232 * not have a credential, so check and see if 1233 * needs to return NSS_ALTRETRY to let the main 1234 * nscd get a chance to process the lookup 1235 */ 1236 if (swret.fallback == 1 && status == NSS_NOTFOUND) { 1237 OM_uint32 stat; 1238 1239 if (gss_inquire_cred(&stat, GSS_C_NO_CREDENTIAL, 1240 NULL, NULL, NULL, NULL) != GSS_S_COMPLETE) { 1241 1242 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 1243 NSCD_LOG_LEVEL_DEBUG) 1244 (me, "NSS_ALTRETRY: fallback to main nscd needed\n"); 1245 1246 status = NSS_ALTRETRY; 1247 } 1248 } 1249 1250 NSCD_SET_STATUS(pbuf, status, -1); 1251 errno = swret.errnum; 1252 1253 /* 1254 * move result/status from args to packed buffer only if 1255 * arg was being used 1256 */ 1257 if (!swret.noarg) 1258 nss_packed_set_status(buffer, length, status, &arg); 1259 1260 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1261 (me, "switch engine result: source is %s, status %d, " 1262 "herrno is %d, errno is %s\n", 1263 (swret.srci != -1) ? NSCD_NSW_SRC_NAME(swret.srci) : "<NOTSET>", 1264 pbuf->p_status, pbuf->p_herrno, strerror(pbuf->p_errno)); 1265 1266 /* clear the TSD key used by the generic initf */ 1267 clear_initf_key(); 1268 pbuf->nscdpriv = 0; 1269 } 1270 1271 static void 1272 nscd_map_contextp(void *buffer, nss_getent_t *contextp, 1273 nssuint_t **cookie_p, nssuint_t **seqnum_p, int setent) 1274 { 1275 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1276 nssuint_t off; 1277 nscd_getent_context_t *ctx; 1278 char *me = "nscd_map_contextp"; 1279 1280 struct cookie_seqnum { 1281 nssuint_t cookie; 1282 nssuint_t seqnum; 1283 } *csp; 1284 1285 if (buffer == NULL) { 1286 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1287 } 1288 1289 off = pbuf->key_off; 1290 csp = (struct cookie_seqnum *)((void *)((char *)buffer + off)); 1291 if (seqnum_p != NULL) 1292 *seqnum_p = &csp->seqnum; 1293 1294 /* 1295 * if called by nss_psetent, and the passed in cookie is 1296 * NSCD_NEW_COOKIE, then there is no cookie yet, return 1297 * a pointer pointing to where the cookie will be stored. 1298 * Also because there is no cookie to validate, just 1299 * return success. 1300 * 1301 * On the other hand, if a cookie is passed in, we need 1302 * to validate the cookie before returning. 1303 */ 1304 if (cookie_p != NULL) 1305 *cookie_p = &csp->cookie; 1306 if (setent == 1 && csp->cookie == NSCD_NEW_COOKIE) { 1307 NSCD_RETURN_STATUS_SUCCESS(pbuf); 1308 } 1309 1310 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1311 (me, "cookie = %lld, sequence number = %lld\n", 1312 csp->cookie, csp->seqnum); 1313 1314 ctx = _nscd_is_getent_ctx(csp->cookie); 1315 1316 if (ctx == NULL) { 1317 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1318 (me, "invalid cookie (%lld)\n", csp->cookie); 1319 1320 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1321 } 1322 1323 if (setent == 1) { 1324 /* if called by nss_psetent, reset the seq number */ 1325 ctx->seq_num = 1; 1326 } else if (ctx->seq_num != (nscd_seq_num_t)csp->seqnum) { 1327 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1328 (me, "invalid sequence number (%lld)\n", csp->seqnum); 1329 1330 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1331 } 1332 1333 contextp->ctx = (struct nss_getent_context *)ctx; 1334 1335 NSCD_RETURN_STATUS_SUCCESS(pbuf); 1336 } 1337 1338 void 1339 nss_psetent(void *buffer, size_t length, pid_t pid) 1340 { 1341 /* inputs */ 1342 nss_db_initf_t initf; 1343 nss_getent_t context = { 0 }; 1344 nss_getent_t *contextp = &context; 1345 nss_status_t status; 1346 nssuint_t *cookiep; 1347 nssuint_t *seqnump; 1348 nscd_getent_context_t *ctx; 1349 int rc; 1350 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1351 nscd_sw_return_t swret = { 0 }, *swrp = &swret; 1352 char *me = "nss_psetent"; 1353 1354 if (buffer == NULL || length == 0) { 1355 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1356 } 1357 1358 /* 1359 * If this is a per-user nscd, and the user does not have 1360 * the necessary credential, return NSS_TRYLOCAL, so the 1361 * setent/getent can be done locally in the process of the 1362 * setent call 1363 */ 1364 if (_whoami == NSCD_CHILD) { 1365 OM_uint32 stat; 1366 1367 if (gss_inquire_cred(&stat, GSS_C_NO_CREDENTIAL, 1368 NULL, NULL, NULL, NULL) != GSS_S_COMPLETE) { 1369 1370 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 1371 NSCD_LOG_LEVEL_DEBUG) 1372 (me, "NSS_TRYLOCAL: fallback to caller process\n"); 1373 NSCD_RETURN_STATUS(pbuf, NSS_TRYLOCAL, 0); 1374 } 1375 } 1376 1377 status = nss_packed_context_init(buffer, length, 1378 NULL, &initf, &contextp, (nss_XbyY_args_t *)NULL); 1379 if (status != NSS_SUCCESS) { 1380 NSCD_RETURN_STATUS(pbuf, status, -1); 1381 } 1382 1383 /* 1384 * use the generic nscd_initf for all the setent requests 1385 * (the TSD key is the pointer to the packed header) 1386 */ 1387 rc = set_initf_key(pbuf); 1388 if (rc != 0) { 1389 NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL); 1390 } 1391 initf = nscd_initf; 1392 1393 /* get address of cookie and seqnum for later updates */ 1394 nscd_map_contextp(buffer, contextp, &cookiep, &seqnump, 1); 1395 if (NSCD_STATUS_IS_NOT_OK(pbuf)) 1396 return; 1397 /* 1398 * pass the packed header buffer pointer to nss_setent 1399 */ 1400 (void) memcpy(&pbuf->nscdpriv, &swrp, sizeof (swrp)); 1401 swret.pbuf = buffer; 1402 1403 /* Perform local setent and set context */ 1404 nss_setent(NULL, initf, contextp); 1405 1406 /* insert cookie info into buffer and return */ 1407 ctx = (nscd_getent_context_t *)contextp->ctx; 1408 if (ctx != NULL) { 1409 *cookiep = ctx->cookie; 1410 *seqnump = (nssuint_t)ctx->seq_num; 1411 ctx->pid = pid; 1412 } else { 1413 /* 1414 * not able to allocate a getent context, the 1415 * client should try the enumeration locally 1416 */ 1417 *cookiep = NSCD_LOCAL_COOKIE; 1418 *seqnump = 0; 1419 } 1420 1421 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1422 (me, "cookie = %lld, sequence number = %lld\n", 1423 *cookiep, *seqnump); 1424 1425 if (ctx != NULL) { 1426 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1427 (me, "cookie = %lld, sequence number = %lld\n", 1428 ctx->cookie, ctx->seq_num); 1429 } 1430 1431 /* clear the TSD key used by the generic initf */ 1432 clear_initf_key(); 1433 1434 if (*cookiep == NSCD_LOCAL_COOKIE) { 1435 NSCD_RETURN_STATUS(pbuf, NSS_TRYLOCAL, 0); 1436 } else { 1437 NSCD_RETURN_STATUS(pbuf, NSS_SUCCESS, 0); 1438 } 1439 } 1440 1441 void 1442 nss_pgetent(void *buffer, size_t length) 1443 { 1444 /* inputs */ 1445 nss_db_initf_t initf; 1446 nss_getent_t context; 1447 nss_getent_t *contextp = &context; 1448 nss_XbyY_args_t arg; 1449 nss_status_t status; 1450 nssuint_t *cookiep; 1451 nssuint_t *seqnump; 1452 nscd_getent_context_t *ctx; 1453 int rc; 1454 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1455 char *me = "nss_pgetent"; 1456 1457 if (buffer == NULL || length == 0) { 1458 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1459 } 1460 1461 status = nss_packed_context_init(buffer, length, 1462 NULL, &initf, &contextp, &arg); 1463 if (status != NSS_SUCCESS) { 1464 NSCD_RETURN_STATUS(pbuf, status, -1); 1465 } 1466 1467 /* 1468 * use the generic nscd_initf for all the getent requests 1469 * (the TSD key is the pointer to the packed header) 1470 */ 1471 rc = set_initf_key(pbuf); 1472 if (rc != 0) { 1473 NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL); 1474 } 1475 initf = nscd_initf; 1476 1477 1478 /* verify the cookie passed in */ 1479 nscd_map_contextp(buffer, contextp, &cookiep, &seqnump, 0); 1480 if (NSCD_STATUS_IS_NOT_OK(pbuf)) 1481 return; 1482 1483 /* Perform local search and pack results into return buffer */ 1484 status = nss_getent(NULL, initf, contextp, &arg); 1485 NSCD_SET_STATUS(pbuf, status, -1); 1486 nss_packed_set_status(buffer, length, status, &arg); 1487 1488 /* increment sequence number in the buffer and nscd context */ 1489 if (status == NSS_SUCCESS) { 1490 ctx = (nscd_getent_context_t *)contextp->ctx; 1491 ctx->seq_num++; 1492 *seqnump = ctx->seq_num; 1493 *cookiep = ctx->cookie; 1494 1495 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1496 (me, "getent OK, new sequence number = %lld, len = %lld," 1497 " data = [ %s ]\n", *seqnump, 1498 pbuf->data_len, (char *)buffer + pbuf->data_off); 1499 } else { 1500 ctx = (nscd_getent_context_t *)contextp->ctx; 1501 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1502 (me, "getent failed, status = %d, sequence number = %lld\n", 1503 status, *seqnump); 1504 } 1505 1506 /* clear the TSD key used by the generic initf */ 1507 clear_initf_key(); 1508 } 1509 1510 void 1511 nss_pendent(void *buffer, size_t length) 1512 { 1513 nss_getent_t context; 1514 nss_getent_t *contextp = &context; 1515 nssuint_t *seqnump; 1516 nssuint_t *cookiep; 1517 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1518 char *me = "nss_pendent"; 1519 1520 if (buffer == NULL || length == 0) { 1521 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1522 } 1523 1524 /* map the contextp from the cookie information */ 1525 nscd_map_contextp(buffer, contextp, &cookiep, &seqnump, 0); 1526 if (NSCD_STATUS_IS_NOT_OK(pbuf)) 1527 return; 1528 1529 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1530 (me, "endent, cookie = %lld, sequence number = %lld\n", 1531 *cookiep, *seqnump); 1532 1533 /* Perform local endent and reset context */ 1534 nss_endent(NULL, NULL, contextp); 1535 NSCD_RETURN_STATUS(pbuf, NSS_SUCCESS, 0); 1536 } 1537 1538 /*ARGSUSED*/ 1539 void 1540 nss_pdelete(void *buffer, size_t length) 1541 { 1542 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1543 1544 /* unnecessary, kept for completeness */ 1545 NSCD_RETURN_STATUS_SUCCESS(pbuf); 1546 } 1547