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