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