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