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