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_gss_func(void **func_p) 441 { 442 char *me = "get_gss_func"; 443 static void *handle = NULL; 444 static mutex_t func_lock = DEFAULTMUTEX; 445 void *sym; 446 char *func_name = "gss_inquire_cred"; 447 static void *func = NULL; 448 449 if (handle != NULL && func_p != NULL && func != NULL) { 450 (void) memcpy(func_p, &func, sizeof (void *)); 451 return (NSCD_SUCCESS); 452 } 453 454 (void) mutex_lock(&func_lock); 455 456 /* close the handle if requested */ 457 if (func_p == NULL) { 458 if (handle != NULL) { 459 (void) dlclose(handle); 460 func = NULL; 461 } 462 (void) mutex_unlock(&func_lock); 463 return (NSCD_SUCCESS); 464 } 465 466 if (handle != NULL && func != NULL) { 467 (void) memcpy(func_p, &func, sizeof (void *)); 468 (void) mutex_unlock(&func_lock); 469 return (NSCD_SUCCESS); 470 } 471 472 if (handle == NULL) { 473 handle = dlopen("libgss.so.1", RTLD_LAZY); 474 if (handle == NULL) { 475 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 476 NSCD_LOG_LEVEL_ERROR) 477 (me, "unable to dlopen libgss.so.1\n"); 478 (void) mutex_unlock(&func_lock); 479 return (NSCD_CFG_DLOPEN_ERROR); 480 } 481 } 482 483 if ((sym = dlsym(handle, func_name)) == NULL) { 484 485 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_ERROR) 486 (me, "unable to find symbol %s\n", func_name); 487 (void) mutex_unlock(&func_lock); 488 return (NSCD_CFG_DLSYM_ERROR); 489 } else { 490 (void) memcpy(func_p, &sym, sizeof (void *)); 491 (void) memcpy(&func, &sym, sizeof (void *)); 492 } 493 494 (void) mutex_unlock(&func_lock); 495 return (NSCD_SUCCESS); 496 } 497 498 static nscd_rc_t 499 get_dns_funcs(int dnsi, void **func_p) 500 { 501 char *me = "get_dns_funcs"; 502 static void *handle = NULL; 503 static mutex_t func_lock = DEFAULTMUTEX; 504 void *sym; 505 char *func_name[2] = { "_nss_get_dns_hosts_name", 506 "_nss_get_dns_ipnodes_name" }; 507 static void *func[2] = {NULL, NULL}; 508 509 if (handle != NULL && dnsi > 0 && func[dnsi] != NULL) { 510 (void) memcpy(func_p, &func[dnsi], sizeof (void *)); 511 return (NSCD_SUCCESS); 512 } 513 514 (void) mutex_lock(&func_lock); 515 516 /* close the handle if requested */ 517 if (dnsi < 0) { 518 if (handle != NULL) { 519 (void) dlclose(handle); 520 func[0] = NULL; 521 func[1] = NULL; 522 } 523 (void) mutex_unlock(&func_lock); 524 return (NSCD_SUCCESS); 525 } 526 527 if (handle != NULL && func[dnsi] != NULL) { 528 (void) memcpy(func_p, &func[dnsi], sizeof (void *)); 529 (void) mutex_unlock(&func_lock); 530 return (NSCD_SUCCESS); 531 } 532 533 if (handle == NULL) { 534 handle = dlopen("nss_dns.so.1", RTLD_LAZY); 535 if (handle == NULL) { 536 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 537 NSCD_LOG_LEVEL_ERROR) 538 (me, "unable to dlopen nss_dns.so.1\n"); 539 (void) mutex_unlock(&func_lock); 540 return (NSCD_CFG_DLOPEN_ERROR); 541 } 542 } 543 544 if ((sym = dlsym(handle, func_name[dnsi])) == NULL) { 545 546 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_ERROR) 547 (me, "unable to find symbol %s\n", func_name[dnsi]); 548 (void) mutex_unlock(&func_lock); 549 return (NSCD_CFG_DLSYM_ERROR); 550 } else { 551 (void) memcpy(func_p, &sym, sizeof (void *)); 552 (void) memcpy(&func[dnsi], &sym, sizeof (void *)); 553 } 554 555 (void) mutex_unlock(&func_lock); 556 return (NSCD_SUCCESS); 557 } 558 559 static nss_status_t 560 search_dns_withttl(nscd_sw_return_t *swret, char *srcname, int dnsi) 561 { 562 nss_status_t (*func)(); 563 nss_status_t res = NSS_UNAVAIL; 564 nscd_rc_t rc; 565 566 swret->noarg = 0; 567 if (strcmp(srcname, "dns") != 0) 568 return (NSS_ERROR); 569 570 rc = get_dns_funcs(dnsi, (void **)&func); 571 if (rc == NSCD_SUCCESS) 572 res = (func)(NULL, &swret->pbuf, &swret->pbufsiz); 573 return (res); 574 } 575 576 /* 577 * Returns a flag to indicate if needs to fall back to the 578 * main nscd when a per-user lookup failed with rc NSS_NOTFOUND. 579 */ 580 static int 581 set_fallback_flag(char *srcname, nss_status_t rc) 582 { 583 char *me = "set_fallback_flag"; 584 if (strcmp(srcname, "ldap") == 0 && rc == NSS_NOTFOUND) { 585 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 586 (me, "NSS_NOTFOUND (ldap): fallback to main nscd " 587 "may be needed\n"); 588 return (1); 589 } 590 return (0); 591 } 592 593 nss_status_t 594 nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum, 595 void *search_args) 596 { 597 char *me = "nss_search"; 598 nss_status_t res = NSS_UNAVAIL; 599 nscd_nsw_state_t *s = NULL; 600 int n_src; 601 unsigned int status_vec = 0; 602 int dbi, srci = -1; 603 int check_loopback = 0; 604 int state_thr = 0; 605 lb_key_t key, *k = NULL; 606 nss_db_root_t root_db; 607 nscd_nsw_params_t params; 608 nscd_sw_return_t *swret; 609 610 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 611 (me, "rootp = %p, initf = %p, search_fnum = %d, " 612 "search_args = %p\n", rootp, initf, 613 search_fnum, search_args); 614 615 NSCD_SW_STATS_G.lookup_request_received_g++; 616 NSCD_SW_STATS_G.lookup_request_in_progress_g++; 617 NSCD_SW_STATS_G.lookup_request_queued_g++; 618 619 /* determine db index, cfg db index, etc */ 620 (void) getparams(search_fnum, initf, ¶ms); 621 dbi = params.dbi; 622 623 /* get address of the switch engine return data area */ 624 if (initf == nscd_initf) { 625 swret = (nscd_sw_return_t *)params.p.private; 626 swret->srci = -1; 627 } else { 628 swret = NULL; 629 params.dnsi = -1; 630 } 631 632 /* 633 * for request that should be processed by the client, 634 * send it back with status NSS_TRYLOCAL 635 */ 636 if (try_local(dbi, search_args) == 1) { 637 res = NSS_TRYLOCAL; 638 goto error_exit; 639 } 640 641 NSCD_SW_STATS(dbi).lookup_request_received++; 642 NSCD_SW_STATS(dbi).lookup_request_in_progress++; 643 NSCD_SW_STATS(dbi).lookup_request_queued++; 644 645 /* if lookup not enabled, return NSS_UNAVAIL */ 646 if (!(NSCD_SW_CFG_G.enable_lookup_g == nscd_true && 647 NSCD_SW_CFG(dbi).enable_lookup == nscd_true)) { 648 649 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 650 (me, "lookup not enabled for %s\n", NSCD_NSW_DB_NAME(dbi)); 651 652 goto error_exit; 653 } 654 655 /* determine if loopback checking is configured */ 656 if (NSCD_SW_CFG_G.enable_loopback_checking_g == nscd_true && 657 NSCD_SW_CFG(dbi).enable_loopback_checking == nscd_true) { 658 check_loopback = 1; 659 660 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 661 (me, "loopback checking enabled for %s\n", 662 NSCD_NSW_DB_NAME(dbi)); 663 } 664 665 if (check_loopback) { 666 k = get_loopback_key(); 667 if (k != NULL) { 668 if (k->dbi != dbi || k->fnum != search_fnum) { 669 clear_loopback_key(k); 670 k = NULL; 671 } 672 } 673 } 674 675 if (s == 0) { 676 nscd_rc_t rc; 677 678 if (check_loopback) { 679 rc = _nscd_get_nsw_state_thread(&root_db, ¶ms); 680 state_thr = 1; 681 } else 682 rc = _nscd_get_nsw_state(&root_db, ¶ms); 683 684 NSCD_SW_STATS_G.lookup_request_queued_g--; 685 NSCD_SW_STATS(dbi).lookup_request_queued--; 686 687 if (rc != NSCD_SUCCESS) 688 goto error_exit; 689 690 s = (nscd_nsw_state_t *)root_db.s; 691 } 692 693 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 694 (me, "database = %s, config = >>%s<<\n", NSCD_NSW_DB_NAME(dbi), 695 (*s->nsw_cfg_p)->nsw_cfg_str); 696 697 for (n_src = 0; n_src < s->max_src; n_src++) { 698 nss_backend_t *be; 699 nss_backend_op_t funcp; 700 struct __nsw_lookup_v1 *lkp; 701 int smf_state; 702 int n_loop = 0; 703 int max_retry = 10; 704 705 res = NSS_UNAVAIL; 706 707 if (n_src == 0) 708 lkp = s->config->lookups; 709 else 710 lkp = lkp->next; 711 712 /* set the number of max. retries */ 713 if (lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES) 714 max_retry = lkp->max_retries; 715 716 srci = (*s->nsw_cfg_p)->src_idx[n_src]; 717 if (swret != NULL) 718 swret->srci = srci; 719 720 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 721 (me, "nsw source = %s\n", NSCD_NSW_SRC_NAME(srci)); 722 723 /* if no privilege to look up, skip */ 724 if (params.privdb == 1 && swret != NULL && 725 strcmp(NSCD_NSW_SRC_NAME(srci), "files") == 0 && 726 _nscd_get_client_euid() != 0) { 727 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 728 NSCD_LOG_LEVEL_DEBUG) 729 (me, "no privilege to look up, skip source\n"); 730 731 goto next_src; 732 } 733 734 /* get state of the (backend) client service */ 735 smf_state = _nscd_get_smf_state(srci, dbi, 0); 736 737 /* stop if the source is one that should be TRYLOCAL */ 738 if (smf_state == NSCD_SVC_STATE_UNKNOWN_SRC) { 739 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 740 NSCD_LOG_LEVEL_DEBUG) 741 (me, "returning TRYLOCAL ... \n"); 742 res = NSS_TRYLOCAL; 743 goto free_nsw_state; 744 } 745 746 if (check_loopback && k != NULL) { 747 748 if (k->srci == srci && k->dbi == dbi) 749 if (k->fnum == search_fnum) { 750 751 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 752 NSCD_LOG_LEVEL_DEBUG) 753 (me, "loopback detected: " 754 "source = %s, database = %s " 755 "search fnum = %d\n", 756 NSCD_NSW_SRC_NAME(srci), 757 NSCD_NSW_DB_NAME(dbi), search_fnum); 758 759 NSCD_SW_STATS_G.loopback_nsw_db_skipped_g++; 760 NSCD_SW_STATS(dbi).loopback_nsw_db_skipped++; 761 continue; 762 } 763 } 764 765 be = s->be[n_src]; 766 if (be != NULL) 767 funcp = NSS_LOOKUP_DBOP(be, search_fnum); 768 769 if ((params.dnsi >= 0 && be == 0) || (params.dnsi < 0 && 770 (be == 0 || (smf_state != NSCD_SVC_STATE_UNINITED && 771 smf_state < SCF_STATE_ONLINE) || funcp == 0))) { 772 773 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 774 NSCD_LOG_LEVEL_DEBUG) 775 (me, "unable to look up source %s: be = %p, " 776 "smf state = %d, funcp = %p\n", 777 NSCD_NSW_SRC_NAME(srci), be, smf_state, funcp); 778 779 goto next_src; 780 } 781 782 do { 783 /* 784 * we can only retry max_retry times, 785 * otherwise threads may get stuck in this 786 * do-while loop forever 787 */ 788 if (n_loop > max_retry) { 789 if (swret != NULL) 790 res = NSS_TRYLOCAL; 791 goto free_nsw_state; 792 } 793 794 /* 795 * set up to prevent loopback 796 */ 797 if (check_loopback && k == NULL) { 798 key.srci = srci; 799 key.dbi = dbi; 800 key.fnum = search_fnum; 801 key.lb_flagp = &check_loopback; 802 (void) set_loopback_key(&key); 803 k = &key; 804 } 805 806 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 807 NSCD_LOG_LEVEL_DEBUG) 808 (me, "looking up source = %s, loop# = %d \n", 809 NSCD_NSW_SRC_NAME(srci), n_loop); 810 811 /* 812 * search the backend, if hosts lookups, 813 * try to get the hosts data with ttl first 814 */ 815 if (params.dnsi >= 0) { 816 res = search_dns_withttl(swret, 817 NSCD_NSW_SRC_NAME(srci), 818 params.dnsi); 819 /* 820 * if not able to get ttl, fall back 821 * to the regular backend call 822 */ 823 if (res == NSS_ERROR) 824 res = (*funcp)(be, search_args); 825 else { 826 /* 827 * status/result are in the 828 * packed buffer, not 829 * search_args 830 */ 831 swret->noarg = 1; 832 } 833 } else 834 res = (*funcp)(be, search_args); 835 if (swret != NULL) 836 swret->errnum = errno; 837 838 /* 839 * backend is not up, check and update the 840 * smf state table 841 */ 842 if (res == NSS_UNAVAIL) 843 (void) _nscd_get_smf_state(srci, dbi, 1); 844 845 /* 846 * may need to fall back to use the main nscd 847 * if per-user lookup 848 */ 849 if (_whoami == NSCD_CHILD && swret != NULL) 850 swret->fallback = set_fallback_flag( 851 NSCD_NSW_SRC_NAME(srci), res); 852 853 _NSCD_LOG_IF(NSCD_LOG_SWITCH_ENGINE, 854 NSCD_LOG_LEVEL_DEBUG) { 855 856 /* 857 * set up to trace the result/status 858 * of the dns/ttl lookup 859 */ 860 if (swret != NULL && swret->noarg == 1) { 861 nss_pheader_t *phdr; 862 struct nss_XbyY_args *arg; 863 arg = (struct nss_XbyY_args *) 864 search_args; 865 phdr = (nss_pheader_t *)swret->pbuf; 866 arg->buf.buffer = (char *)phdr + 867 phdr->data_off; 868 arg->returnlen = phdr->data_len; 869 if (phdr->p_errno == ERANGE) 870 arg->erange = 1; 871 arg->h_errno = phdr->p_herrno; 872 } 873 874 trace_result(dbi, srci, search_fnum, res, 875 (nss_XbyY_args_t *)search_args); 876 } 877 878 n_loop++; 879 } while (retry_test(res, n_loop, lkp)); 880 881 next_src: 882 883 status_vec |= (1 << res); 884 885 if (__NSW_ACTION_V1(lkp, res) == __NSW_RETURN) { 886 break; 887 } 888 } 889 890 free_nsw_state: 891 892 if (state_thr == 1) 893 _nscd_put_nsw_state_thread(s); 894 else 895 _nscd_put_nsw_state(s); 896 if (check_loopback && k != NULL) 897 clear_loopback_key(k); 898 899 if (res != NSS_SUCCESS) 900 goto error_exit; 901 902 NSCD_SW_STATS_G.lookup_request_succeeded_g++; 903 NSCD_SW_STATS(dbi).lookup_request_succeeded++; 904 NSCD_SW_STATS_G.lookup_request_in_progress_g--; 905 NSCD_SW_STATS(dbi).lookup_request_in_progress--; 906 907 return (NSS_SUCCESS); 908 909 error_exit: 910 911 NSCD_SW_STATS_G.lookup_request_failed_g++; 912 NSCD_SW_STATS_G.lookup_request_in_progress_g--; 913 NSCD_SW_STATS(dbi).lookup_request_failed++; 914 NSCD_SW_STATS(dbi).lookup_request_in_progress--; 915 916 return (res); 917 } 918 919 920 /* ===> get/set/endent */ 921 922 static void nss_setent_u(nss_db_root_t *, 923 nss_db_initf_t, 924 nss_getent_t *); 925 static nss_status_t nss_getent_u(nss_db_root_t *, 926 nss_db_initf_t, 927 nss_getent_t *, 928 void *); 929 static void nss_endent_u(nss_db_root_t *, 930 nss_db_initf_t, 931 nss_getent_t *); 932 933 void 934 nss_setent(nss_db_root_t *rootp, nss_db_initf_t initf, 935 nss_getent_t *contextpp) 936 { 937 if (contextpp == 0) 938 return; 939 nss_setent_u(rootp, initf, contextpp); 940 } 941 942 nss_status_t 943 nss_getent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp, 944 void *args) 945 { 946 nss_status_t status; 947 948 if (contextpp == 0) { 949 return (NSS_UNAVAIL); 950 } 951 status = nss_getent_u(rootp, initf, contextpp, args); 952 return (status); 953 } 954 955 void 956 nss_endent(nss_db_root_t *rootp, nss_db_initf_t initf, 957 nss_getent_t *contextpp) 958 { 959 if (contextpp == 0) 960 return; 961 nss_endent_u(rootp, initf, contextpp); 962 } 963 964 /*ARGSUSED*/ 965 static void 966 end_iter_u(nss_db_root_t *rootp, struct nss_getent_context *contextp) 967 { 968 nscd_getent_context_t *ctx; 969 nscd_nsw_state_t *s; 970 nss_backend_t *be; 971 int n_src; 972 973 ctx = (nscd_getent_context_t *)contextp; 974 s = ctx->nsw_state; 975 n_src = ctx->n_src; 976 be = ctx->be; 977 978 if (s != 0) { 979 if (n_src < s->max_src && be != 0) { 980 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0); 981 ctx->be = 0; /* Should be unnecessary, but hey */ 982 } 983 } 984 ctx->n_src = 0; 985 } 986 987 static void 988 nss_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf, 989 nss_getent_t *contextpp) 990 { 991 char *me = "nss_setent_u"; 992 nscd_nsw_state_t *s; 993 nscd_getent_context_t *contextp; 994 nscd_nsw_params_t params; 995 nss_db_root_t root; 996 nss_backend_t *be; 997 int n_src, i; 998 nscd_sw_return_t *swret = NULL; 999 1000 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1001 (me, "rootp = %p, initf = %p, contextpp = %p \n", 1002 rootp, initf, contextpp); 1003 1004 /* get the nsw db index via the initf function */ 1005 (void) getparams(-1, initf, ¶ms); 1006 1007 /* get address of the switch engine return data area */ 1008 if (initf == nscd_initf) 1009 swret = (nscd_sw_return_t *)params.p.private; 1010 1011 /* if no privilege to look up, return */ 1012 if (params.privdb == 1 && swret != NULL && 1013 ((nss_pheader_t *)(swret->pbuf))->p_euid != 0) { 1014 1015 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1016 (me, "no privilege \n"); 1017 return; 1018 } 1019 1020 if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) { 1021 if ((_nscd_get_getent_ctx(contextpp, ¶ms)) != 1022 NSCD_SUCCESS) { 1023 return; 1024 } 1025 contextp = (nscd_getent_context_t *)contextpp->ctx; 1026 } 1027 s = contextp->nsw_state; 1028 1029 if (s == 0) { 1030 if (_nscd_get_nsw_state(&root, ¶ms) != 1031 NSCD_SUCCESS) { 1032 return; 1033 } 1034 s = (nscd_nsw_state_t *)root.s; 1035 contextp->nsw_state = s; 1036 1037 } else { 1038 s = contextp->nsw_state; 1039 n_src = contextp->n_src; 1040 be = contextp->be; 1041 if (n_src == 0 && be != 0) { 1042 /* 1043 * Optimization: don't do endent, don't change 1044 * backends, just do the setent. Look Ma, no locks 1045 * (nor any context that needs updating). 1046 */ 1047 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0); 1048 return; 1049 } 1050 if (n_src < s->max_src && be != 0) { 1051 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0); 1052 contextp->be = 0; /* Play it safe */ 1053 } 1054 } 1055 for (n_src = 0, be = 0; n_src < s->max_src && 1056 (be = s->be[n_src]) == 0; n_src++) { 1057 ; 1058 } 1059 1060 contextp->n_src = n_src; 1061 contextp->be = be; 1062 1063 if (be == 0) { 1064 /* Things are broken enough that we can't do setent/getent */ 1065 nss_endent_u(rootp, initf, contextpp); 1066 return; 1067 } 1068 1069 /* 1070 * make sure all the backends are supported 1071 */ 1072 for (i = 0; i < s->max_src; i++) { 1073 int st, srci; 1074 1075 srci = (*s->nsw_cfg_p)->src_idx[i]; 1076 st = _nscd_get_smf_state(srci, params.dbi, 1); 1077 if (st == NSCD_SVC_STATE_UNKNOWN_SRC || 1078 st == NSCD_SVC_STATE_UNINITED) { 1079 nss_endent_u(rootp, initf, contextpp); 1080 1081 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 1082 NSCD_LOG_LEVEL_DEBUG) 1083 (me, "backend (%s) not available (state = %d)\n", 1084 NSCD_NSW_SRC_NAME(srci), st); 1085 1086 return; 1087 } 1088 } 1089 1090 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0); 1091 } 1092 1093 nss_status_t 1094 nss_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf, 1095 nss_getent_t *contextpp, void *args) 1096 { 1097 char *me = "nss_getent_u"; 1098 nscd_nsw_state_t *s; 1099 nscd_getent_context_t *contextp; 1100 int n_src; 1101 nss_backend_t *be; 1102 1103 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1104 (me, "rootp = %p, initf = %p, contextpp = %p, args = %p\n", 1105 rootp, initf, contextpp, args); 1106 1107 if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) { 1108 nss_setent_u(rootp, initf, contextpp); 1109 if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) { 1110 /* Give up */ 1111 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 1112 NSCD_LOG_LEVEL_ERROR) 1113 (me, "not able to obtain getent context ... give up\n"); 1114 1115 return (NSS_UNAVAIL); 1116 } 1117 } 1118 1119 s = contextp->nsw_state; 1120 n_src = contextp->n_src; 1121 be = contextp->be; 1122 1123 if (s == 0) { 1124 /* 1125 * We've done an end_iter() and haven't done nss_setent() 1126 * or nss_endent() since; we should stick in this state 1127 * until the caller invokes one of those two routines. 1128 */ 1129 return (NSS_SUCCESS); 1130 } 1131 1132 while (n_src < s->max_src) { 1133 nss_status_t res; 1134 struct __nsw_lookup_v1 *lkp = NULL; 1135 int n; 1136 1137 /* get the nsw config for the current source */ 1138 lkp = s->config->lookups; 1139 for (n = 0; n < n_src; n++) 1140 lkp = lkp->next; 1141 1142 if (be == 0) { 1143 /* If it's null it's a bug, but let's play safe */ 1144 res = NSS_UNAVAIL; 1145 } else { 1146 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 1147 NSCD_LOG_LEVEL_DEBUG) 1148 (me, "database: %s, backend: %s, nsswitch config: %s\n", 1149 NSCD_NSW_DB_NAME(s->dbi), 1150 lkp->service_name, 1151 (*s->nsw_cfg_p)->nsw_cfg_str); 1152 1153 res = NSS_INVOKE_DBOP(be, NSS_DBOP_GETENT, args); 1154 } 1155 1156 if (__NSW_ACTION_V1(lkp, res) == __NSW_RETURN) { 1157 if (res != __NSW_SUCCESS) { 1158 end_iter_u(rootp, 1159 (struct nss_getent_context *)contextp); 1160 } 1161 return (res); 1162 } 1163 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0); 1164 do { 1165 n_src++; 1166 } while (n_src < s->max_src && 1167 (be = s->be[n_src]) == 0); 1168 if (be == 0) { 1169 /* 1170 * This is the case where we failed to get the backend 1171 * for the last source. We exhausted all sources. 1172 */ 1173 nss_endent_u(rootp, initf, contextpp); 1174 return (NSS_SUCCESS); 1175 } 1176 contextp->n_src = n_src; 1177 contextp->be = be; 1178 (void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0); 1179 } 1180 /* Got to the end of the sources without finding another entry */ 1181 end_iter_u(rootp, (struct nss_getent_context *)contextp); 1182 return (NSS_SUCCESS); 1183 /* success is either a successful entry or end of the sources */ 1184 } 1185 1186 /*ARGSUSED*/ 1187 void 1188 nss_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf, 1189 nss_getent_t *contextpp) 1190 { 1191 char *me = "nss_endent_u"; 1192 nscd_getent_context_t *contextp; 1193 1194 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1195 (me, "rootp = %p, initf = %p, contextpp = %p \n", 1196 rootp, initf, contextpp); 1197 1198 if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) { 1199 /* nss_endent() on an unused context is a no-op */ 1200 return; 1201 } 1202 end_iter_u(rootp, (struct nss_getent_context *)contextp); 1203 _nscd_put_getent_ctx(contextp); 1204 contextpp->ctx = NULL; 1205 } 1206 1207 /* 1208 * _nss_db_state_destr() and nss_delete() do nothing in nscd 1209 * but is needed to make the caller (below nscd) happy 1210 */ 1211 /*ARGSUSED*/ 1212 void 1213 _nss_db_state_destr(struct nss_db_state *s) 1214 { 1215 /* nsw state in nscd is always reused, so do nothing here */ 1216 } 1217 1218 /*ARGSUSED*/ 1219 void 1220 nss_delete(nss_db_root_t *rootp) 1221 { 1222 /* 1223 * the only resource kept tracked by the nss_db_root_t 1224 * is the nsw state which is always reused and no need 1225 * to be freed. So just return. 1226 */ 1227 } 1228 1229 /* 1230 * Start of nss_psearch/nss_psetent()/nss_pgetent()/nss_pendent() 1231 * buffers switch entry points 1232 */ 1233 1234 /* 1235 * nss_psearch opens a packed structure header, assembles a local 1236 * nss_XbyY_args_t structure and calls the local copy of nss_search. 1237 * The return data is assembled in "files native format" in the 1238 * return buffer location. Status if packed back up with the buffer 1239 * and the whole wad is returned to the cache or the client. 1240 */ 1241 1242 void 1243 nss_psearch(void *buffer, size_t length) 1244 { 1245 /* inputs */ 1246 nss_db_initf_t initf; 1247 int dbop; 1248 int rc; 1249 nss_XbyY_args_t arg; 1250 nss_status_t status; 1251 nscd_sw_return_t swret = { 0 }, *swrp = &swret; 1252 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1253 char *me = "nss_psearch"; 1254 1255 if (buffer == NULL || length == 0) { 1256 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1257 } 1258 1259 status = nss_packed_arg_init(buffer, length, 1260 NULL, &initf, &dbop, &arg); 1261 if (status != NSS_SUCCESS) { 1262 NSCD_RETURN_STATUS(pbuf, status, -1); 1263 } 1264 1265 /* 1266 * pass the address of the return data area 1267 * for the switch engine to return its own data 1268 */ 1269 (void) memcpy(&pbuf->nscdpriv, &swrp, sizeof (swrp)); 1270 swret.pbuf = buffer; 1271 swret.pbufsiz = length; 1272 1273 /* 1274 * use the generic nscd_initf for all database lookups 1275 * (the TSD key is the pointer to the packed header) 1276 */ 1277 rc = set_initf_key(pbuf); 1278 if (rc != 0) { 1279 NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL); 1280 } 1281 initf = nscd_initf; 1282 1283 /* Perform local search and pack results into return buffer */ 1284 /* nscd's search ignores db_root */ 1285 status = nss_search(NULL, initf, dbop, &arg); 1286 1287 /* 1288 * If status is NSS_NOTFOUND and ldap also returned 1289 * NSS_NOTFOUND, it is possible that the user does 1290 * not have a credential, so check and see if 1291 * needs to return NSS_ALTRETRY to let the main 1292 * nscd get a chance to process the lookup 1293 */ 1294 if (swret.fallback == 1 && status == NSS_NOTFOUND) { 1295 OM_uint32 (*func)(); 1296 OM_uint32 stat; 1297 nscd_rc_t rc; 1298 1299 rc = get_gss_func((void **)&func); 1300 if (rc == NSCD_SUCCESS) { 1301 if (func(&stat, GSS_C_NO_CREDENTIAL, 1302 NULL, NULL, NULL, NULL) != GSS_S_COMPLETE) { 1303 1304 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 1305 NSCD_LOG_LEVEL_DEBUG) 1306 (me, "NSS_ALTRETRY: fallback to main nscd needed\n"); 1307 1308 status = NSS_ALTRETRY; 1309 } 1310 } 1311 } 1312 1313 NSCD_SET_STATUS(pbuf, status, -1); 1314 errno = swret.errnum; 1315 1316 /* 1317 * move result/status from args to packed buffer only if 1318 * arg was being used 1319 */ 1320 if (!swret.noarg) 1321 nss_packed_set_status(buffer, length, status, &arg); 1322 1323 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1324 (me, "switch engine result: source is %s, status %d, " 1325 "herrno is %d, errno is %s\n", 1326 (swret.srci != -1) ? NSCD_NSW_SRC_NAME(swret.srci) : "<NOTSET>", 1327 pbuf->p_status, pbuf->p_herrno, strerror(pbuf->p_errno)); 1328 1329 /* clear the TSD key used by the generic initf */ 1330 clear_initf_key(); 1331 pbuf->nscdpriv = 0; 1332 } 1333 1334 static void 1335 nscd_map_contextp(void *buffer, nss_getent_t *contextp, 1336 nssuint_t **cookie_num_p, nssuint_t **seqnum_p, int setent) 1337 { 1338 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1339 nssuint_t off; 1340 nscd_getent_context_t *ctx; 1341 char *me = "nscd_map_contextp"; 1342 nscd_getent_p1_cookie_t *cookie; 1343 1344 if (buffer == NULL) { 1345 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1346 } 1347 1348 off = pbuf->key_off; 1349 cookie = (nscd_getent_p1_cookie_t *)((void *)((char *)buffer + off)); 1350 if (seqnum_p != NULL) 1351 *seqnum_p = &cookie->p1_seqnum; 1352 1353 /* 1354 * if called by nss_psetent, and the passed in cookie number 1355 * is NSCD_NEW_COOKIE, then there is no cookie yet, return a 1356 * pointer pointing to where the cookie number will be stored. 1357 * Also because there is no cookie to validate, just return 1358 * success. 1359 * 1360 * On the other hand, if a cookie number is passed in, we need 1361 * to validate the cookie number before returning. 1362 */ 1363 if (cookie_num_p != NULL) 1364 *cookie_num_p = &cookie->p1_cookie_num; 1365 if (setent == 1 && cookie->p1_cookie_num == NSCD_NEW_COOKIE) { 1366 NSCD_RETURN_STATUS_SUCCESS(pbuf); 1367 } 1368 1369 /* 1370 * If the sequence number and start time match nscd's p0 cookie, 1371 * then either setent was done twice in a row or this is the 1372 * first getent after the setent, return success as well. 1373 */ 1374 if (cookie->p1_seqnum == NSCD_P0_COOKIE_SEQNUM) { 1375 nscd_getent_p0_cookie_t *p0c = 1376 (nscd_getent_p0_cookie_t *)cookie; 1377 if (p0c->p0_time == _nscd_get_start_time()) 1378 NSCD_RETURN_STATUS_SUCCESS(pbuf); 1379 } 1380 1381 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1382 (me, "cookie # = %lld, sequence # = %lld\n", 1383 cookie->p1_cookie_num, cookie->p1_seqnum); 1384 1385 ctx = _nscd_is_getent_ctx(cookie->p1_cookie_num); 1386 1387 if (ctx == NULL) { 1388 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1389 (me, "invalid cookie # (%lld)\n", cookie->p1_cookie_num); 1390 1391 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1392 } 1393 1394 /* if not called by nss_psetent, verify sequence number */ 1395 if (setent != 1 && ctx->seq_num != 1396 (nscd_seq_num_t)cookie->p1_seqnum) { 1397 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1398 (me, "invalid sequence # (%lld)\n", cookie->p1_seqnum); 1399 1400 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1401 } 1402 1403 contextp->ctx = (struct nss_getent_context *)ctx; 1404 1405 NSCD_RETURN_STATUS_SUCCESS(pbuf); 1406 } 1407 1408 void 1409 nss_psetent(void *buffer, size_t length, pid_t pid) 1410 { 1411 nss_getent_t context = { 0 }; 1412 nss_getent_t *contextp = &context; 1413 nssuint_t *cookie_num_p; 1414 nssuint_t *seqnum_p; 1415 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1416 nscd_getent_p0_cookie_t *p0c; 1417 char *me = "nss_psetent"; 1418 1419 if (buffer == NULL || length == 0) { 1420 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1421 } 1422 1423 /* 1424 * If this is a per-user nscd, and the user does not have 1425 * the necessary credential, return NSS_TRYLOCAL, so the 1426 * setent/getent can be done locally in the process of the 1427 * setent call 1428 */ 1429 if (_whoami == NSCD_CHILD) { 1430 OM_uint32 (*func)(); 1431 OM_uint32 stat; 1432 nscd_rc_t rc; 1433 1434 rc = get_gss_func((void **)&func); 1435 if (rc == NSCD_SUCCESS) { 1436 if (func(&stat, GSS_C_NO_CREDENTIAL, 1437 NULL, NULL, NULL, NULL) != GSS_S_COMPLETE) { 1438 1439 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, 1440 NSCD_LOG_LEVEL_DEBUG) 1441 (me, "NSS_TRYLOCAL: fallback to caller process\n"); 1442 NSCD_RETURN_STATUS(pbuf, NSS_TRYLOCAL, 0); 1443 } 1444 } 1445 } 1446 1447 /* check cookie number */ 1448 nscd_map_contextp(buffer, contextp, &cookie_num_p, &seqnum_p, 1); 1449 if (NSCD_STATUS_IS_NOT_OK(pbuf)) 1450 return; 1451 1452 /* set cookie number and sequence number */ 1453 p0c = (nscd_getent_p0_cookie_t *)cookie_num_p; 1454 if (contextp->ctx == NULL) { 1455 /* 1456 * first setent (no existing getent context), 1457 * return a p0 cookie 1458 */ 1459 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1460 (me, "first setent, no getent context yet\n"); 1461 } else { 1462 /* 1463 * doing setent on an existing getent context, 1464 * release resources allocated and return a 1465 * p0 cookie 1466 */ 1467 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1468 (me, "setent resetting sequence number = %lld\n", *seqnum_p); 1469 1470 _nscd_put_getent_ctx((nscd_getent_context_t *)contextp->ctx); 1471 contextp->ctx = NULL; 1472 } 1473 1474 p0c->p0_pid = pid; 1475 p0c->p0_time = _nscd_get_start_time(); 1476 p0c->p0_seqnum = NSCD_P0_COOKIE_SEQNUM; 1477 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1478 (me, "returning a p0 cookie: pid = %ld, time = %ld, seq #= %llx\n", 1479 p0c->p0_pid, p0c->p0_time, p0c->p0_seqnum); 1480 1481 NSCD_RETURN_STATUS(pbuf, NSS_SUCCESS, 0); 1482 } 1483 1484 static void 1485 delayed_setent(nss_pheader_t *pbuf, nss_db_initf_t initf, 1486 nss_getent_t *contextp, nssuint_t *cookie_num_p, 1487 nssuint_t *seqnum_p, pid_t pid) 1488 { 1489 nscd_getent_context_t *ctx; 1490 nscd_sw_return_t swret = { 0 }, *swrp = &swret; 1491 char *me = "delayed_setent"; 1492 1493 /* 1494 * check credential 1495 */ 1496 _nscd_APP_check_cred(pbuf, &pid, "NSCD_DELAYED_SETENT", 1497 NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_ERROR); 1498 if (NSCD_STATUS_IS_NOT_OK(pbuf)) { 1499 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1500 (me, "invalid credential\n"); 1501 return; 1502 } 1503 1504 /* 1505 * pass the packed header buffer pointer to nss_setent 1506 */ 1507 (void) memcpy(&pbuf->nscdpriv, &swrp, sizeof (swrp)); 1508 swret.pbuf = pbuf; 1509 1510 /* Perform local setent and set context */ 1511 nss_setent(NULL, initf, contextp); 1512 1513 /* insert cookie info into packed buffer header */ 1514 ctx = (nscd_getent_context_t *)contextp->ctx; 1515 if (ctx != NULL) { 1516 *cookie_num_p = ctx->cookie_num; 1517 *seqnum_p = ctx->seq_num; 1518 ctx->pid = pid; 1519 } else { 1520 /* 1521 * not able to allocate a getent context, the 1522 * client should try the enumeration locally 1523 */ 1524 *cookie_num_p = NSCD_LOCAL_COOKIE; 1525 *seqnum_p = 0; 1526 1527 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1528 (me, "NSS_TRYLOCAL: cookie # = %lld, sequence # = %lld\n", 1529 *cookie_num_p, *seqnum_p); 1530 NSCD_RETURN_STATUS(pbuf, NSS_TRYLOCAL, 0); 1531 } 1532 1533 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1534 (me, "NSS_SUCCESS: cookie # = %lld, sequence # = %lld\n", 1535 ctx->cookie_num, ctx->seq_num); 1536 1537 NSCD_RETURN_STATUS(pbuf, NSS_SUCCESS, 0); 1538 } 1539 1540 void 1541 nss_pgetent(void *buffer, size_t length) 1542 { 1543 /* inputs */ 1544 nss_db_initf_t initf; 1545 nss_getent_t context = { 0 }; 1546 nss_getent_t *contextp = &context; 1547 nss_XbyY_args_t arg = { 0}; 1548 nss_status_t status; 1549 nssuint_t *cookie_num_p; 1550 nssuint_t *seqnum_p; 1551 nscd_getent_context_t *ctx; 1552 int rc; 1553 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1554 char *me = "nss_pgetent"; 1555 1556 if (buffer == NULL || length == 0) { 1557 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1558 } 1559 1560 /* verify the cookie passed in */ 1561 nscd_map_contextp(buffer, contextp, &cookie_num_p, &seqnum_p, 0); 1562 if (NSCD_STATUS_IS_NOT_OK(pbuf)) 1563 return; 1564 /* 1565 * use the generic nscd_initf for all the getent requests 1566 * (the TSD key is the pointer to the packed header) 1567 */ 1568 rc = set_initf_key(pbuf); 1569 if (rc != 0) { 1570 NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL); 1571 } 1572 initf = nscd_initf; 1573 1574 /* if no context yet, get one */ 1575 if (contextp->ctx == NULL) { 1576 nscd_getent_p0_cookie_t *p0c = 1577 (nscd_getent_p0_cookie_t *)cookie_num_p; 1578 1579 delayed_setent(pbuf, initf, contextp, cookie_num_p, 1580 seqnum_p, p0c->p0_pid); 1581 if (NSCD_STATUS_IS_NOT_OK(pbuf)) { 1582 clear_initf_key(); 1583 return; 1584 } 1585 } 1586 1587 status = nss_packed_context_init(buffer, length, 1588 NULL, &initf, &contextp, &arg); 1589 if (status != NSS_SUCCESS) { 1590 NSCD_RETURN_STATUS(pbuf, status, -1); 1591 } 1592 1593 /* Perform local search and pack results into return buffer */ 1594 status = nss_getent(NULL, initf, contextp, &arg); 1595 NSCD_SET_STATUS(pbuf, status, -1); 1596 nss_packed_set_status(buffer, length, status, &arg); 1597 1598 /* increment sequence number in the buffer and nscd context */ 1599 if (status == NSS_SUCCESS) { 1600 ctx = (nscd_getent_context_t *)contextp->ctx; 1601 ctx->seq_num++; 1602 *seqnum_p = ctx->seq_num; 1603 *cookie_num_p = ctx->cookie_num; 1604 1605 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1606 (me, "getent OK, new sequence # = %lld, len = %lld," 1607 " data = >>%s<<\n", *seqnum_p, 1608 pbuf->data_len, (char *)buffer + pbuf->data_off); 1609 } else { 1610 /* release the resources used */ 1611 ctx = (nscd_getent_context_t *)contextp->ctx; 1612 if (ctx != NULL) { 1613 _nscd_put_getent_ctx(ctx); 1614 contextp->ctx = NULL; 1615 } 1616 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1617 (me, "getent failed, status = %d, sequence # = %lld\n", 1618 status, *seqnum_p); 1619 } 1620 1621 /* clear the TSD key used by the generic initf */ 1622 clear_initf_key(); 1623 } 1624 1625 void 1626 nss_pendent(void *buffer, size_t length) 1627 { 1628 nss_getent_t context = { 0 }; 1629 nss_getent_t *contextp = &context; 1630 nssuint_t *seqnum_p; 1631 nssuint_t *cookie_num_p; 1632 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1633 char *me = "nss_pendent"; 1634 1635 if (buffer == NULL || length == 0) { 1636 NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); 1637 } 1638 1639 /* map the contextp from the cookie information */ 1640 nscd_map_contextp(buffer, contextp, &cookie_num_p, &seqnum_p, 0); 1641 if (NSCD_STATUS_IS_NOT_OK(pbuf)) 1642 return; 1643 1644 if (contextp->ctx == NULL) 1645 return; 1646 1647 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) 1648 (me, "endent, cookie = %lld, sequence # = %lld\n", 1649 *cookie_num_p, *seqnum_p); 1650 1651 /* Perform local endent and reset context */ 1652 nss_endent(NULL, NULL, contextp); 1653 NSCD_RETURN_STATUS(pbuf, NSS_SUCCESS, 0); 1654 } 1655 1656 /*ARGSUSED*/ 1657 void 1658 nss_pdelete(void *buffer, size_t length) 1659 { 1660 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 1661 1662 /* unnecessary, kept for completeness */ 1663 NSCD_RETURN_STATUS_SUCCESS(pbuf); 1664 } 1665