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