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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdlib.h> 27 #include <assert.h> 28 #include <string.h> 29 #include <errno.h> 30 #include <fcntl.h> 31 #include "nscd_db.h" 32 #include "nscd_log.h" 33 #include "nscd_switch.h" 34 #include "nscd_door.h" 35 36 extern int _whoami; 37 static mutex_t getent_monitor_mutex = DEFAULTMUTEX; 38 static int getent_monitor_started = 0; 39 40 static rwlock_t getent_ctxDB_rwlock = DEFAULTRWLOCK; 41 static nscd_db_t *getent_ctxDB = NULL; 42 43 /* 44 * internal structure representing a nscd getent context 45 */ 46 typedef struct nscd_getent_ctx { 47 int to_delete; /* this ctx no longer valid */ 48 nscd_getent_context_t *ptr; 49 nscd_cookie_num_t cookie_num; 50 } nscd_getent_ctx_t; 51 52 /* 53 * nscd_getent_context_t list for each nss database. Protected 54 * by the readers/writer lock nscd_getent_ctx_lock. 55 */ 56 nscd_getent_ctx_base_t **nscd_getent_ctx_base; 57 static rwlock_t nscd_getent_ctx_base_lock = DEFAULTRWLOCK; 58 59 extern nscd_db_entry_t *_nscd_walk_db(nscd_db_t *db, void **cookie); 60 61 static nscd_rc_t _nscd_init_getent_ctx_monitor(); 62 63 /* 64 * FUNCTION: _nscd_create_getent_ctxDB 65 * 66 * Create the internal getent context database to keep track of the 67 * getent contexts currently being used. 68 */ 69 nscd_db_t * 70 _nscd_create_getent_ctxDB() 71 { 72 73 nscd_db_t *ret; 74 75 (void) rw_wrlock(&getent_ctxDB_rwlock); 76 77 if (getent_ctxDB != NULL) { 78 (void) rw_unlock(&getent_ctxDB_rwlock); 79 return (getent_ctxDB); 80 } 81 82 ret = _nscd_alloc_db(NSCD_DB_SIZE_LARGE); 83 84 if (ret != NULL) 85 getent_ctxDB = ret; 86 87 (void) rw_unlock(&getent_ctxDB_rwlock); 88 89 return (ret); 90 } 91 92 /* 93 * FUNCTION: _nscd_add_getent_ctx 94 * 95 * Add a getent context to the internal context database. 96 */ 97 static nscd_rc_t 98 _nscd_add_getent_ctx( 99 nscd_getent_context_t *ptr, 100 nscd_cookie_num_t cookie_num) 101 { 102 int size; 103 char buf[32]; 104 nscd_db_entry_t *db_entry; 105 nscd_getent_ctx_t *gnctx; 106 107 if (ptr == NULL) 108 return (NSCD_INVALID_ARGUMENT); 109 110 (void) snprintf(buf, sizeof (buf), "%lld", cookie_num); 111 112 size = sizeof (*gnctx); 113 114 db_entry = _nscd_alloc_db_entry(NSCD_DATA_CTX_ADDR, 115 (const char *)buf, size, 1, 1); 116 if (db_entry == NULL) 117 return (NSCD_NO_MEMORY); 118 119 gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); 120 gnctx->ptr = ptr; 121 gnctx->cookie_num = cookie_num; 122 123 (void) rw_wrlock(&getent_ctxDB_rwlock); 124 (void) _nscd_add_db_entry(getent_ctxDB, buf, db_entry, 125 NSCD_ADD_DB_ENTRY_FIRST); 126 (void) rw_unlock(&getent_ctxDB_rwlock); 127 128 return (NSCD_SUCCESS); 129 } 130 131 /* 132 * FUNCTION: _nscd_is_getent_ctx 133 * 134 * Check to see if a getent context can be found in the internal 135 * getent context database. 136 */ 137 nscd_getent_context_t * 138 _nscd_is_getent_ctx( 139 nscd_cookie_num_t cookie_num) 140 { 141 char ptrstr[32]; 142 const nscd_db_entry_t *db_entry; 143 nscd_getent_context_t *ret = NULL; 144 char *me = "_nscd_is_getent_ctx"; 145 146 (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num); 147 148 (void) rw_rdlock(&getent_ctxDB_rwlock); 149 150 db_entry = _nscd_get_db_entry(getent_ctxDB, NSCD_DATA_CTX_ADDR, 151 (const char *)ptrstr, NSCD_GET_FIRST_DB_ENTRY, 0); 152 153 if (db_entry != NULL) { 154 nscd_getent_ctx_t *gnctx; 155 156 gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); 157 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 158 (me, "getent context %p, cookie# %lld, to_delete %d\n", 159 gnctx->ptr, gnctx->cookie_num, gnctx->to_delete); 160 161 /* 162 * If the ctx is not to be deleted and the cookie numbers 163 * match, return the ctx if not aborted and not in use. 164 * Otherwise return NULL. 165 */ 166 if (gnctx->to_delete == 0 && gnctx->cookie_num == cookie_num) { 167 ret = gnctx->ptr; 168 (void) mutex_lock(&gnctx->ptr->getent_mutex); 169 if (ret->aborted == 1 || ret->in_use == 1) 170 ret = NULL; 171 else 172 ret->in_use = 1; 173 (void) mutex_unlock(&gnctx->ptr->getent_mutex); 174 } 175 } 176 177 (void) rw_unlock(&getent_ctxDB_rwlock); 178 179 return (ret); 180 } 181 182 int 183 _nscd_is_getent_ctx_in_use( 184 nscd_getent_context_t *ctx) 185 { 186 int in_use; 187 char *me = "_nscd_getent_ctx_in_use"; 188 189 (void) mutex_lock(&ctx->getent_mutex); 190 191 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 192 (me, "in_use = %d, ctx->thr_id = %d, thread id = %d\n", 193 ctx->in_use, ctx->thr_id, thr_self()); 194 195 in_use = ctx->in_use; 196 if (in_use == 1 && ctx->thr_id == thr_self()) 197 in_use = 0; 198 (void) mutex_unlock(&ctx->getent_mutex); 199 return (in_use); 200 } 201 202 /* 203 * FUNCTION: _nscd_free_ctx_if_aborted 204 * 205 * Check to see if the getent session associated with a getent context had 206 * been aborted. If so, return the getent context back to the pool. 207 */ 208 void 209 _nscd_free_ctx_if_aborted( 210 nscd_getent_context_t *ctx) 211 { 212 int aborted; 213 char *me = "_nscd_free_ctx_if_aborted"; 214 215 (void) mutex_lock(&ctx->getent_mutex); 216 217 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 218 (me, "in_use = %d, aborted = %d\n", ctx->in_use, ctx->aborted); 219 220 if (ctx->in_use != 1) { 221 (void) mutex_unlock(&ctx->getent_mutex); 222 return; 223 } 224 aborted = ctx->aborted; 225 ctx->in_use = 0; 226 (void) mutex_unlock(&ctx->getent_mutex); 227 228 if (aborted == 1) { 229 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 230 (me, "getent session aborted, return the getent context\n"); 231 _nscd_put_getent_ctx(ctx); 232 } 233 } 234 235 /* 236 * FUNCTION: _nscd_del_getent_ctx 237 * 238 * Delete a getent context from the internal getent context database. 239 */ 240 static void 241 _nscd_del_getent_ctx( 242 nscd_getent_context_t *ptr, 243 nscd_cookie_num_t cookie_num) 244 { 245 char ptrstr[32]; 246 nscd_getent_ctx_t *gnctx; 247 const nscd_db_entry_t *db_entry; 248 249 if (ptr == NULL) 250 return; 251 252 (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num); 253 254 (void) rw_rdlock(&getent_ctxDB_rwlock); 255 /* 256 * first find the db entry and make sure the 257 * sequence number matched, then delete it from 258 * the database. 259 */ 260 db_entry = _nscd_get_db_entry(getent_ctxDB, 261 NSCD_DATA_CTX_ADDR, 262 (const char *)ptrstr, 263 NSCD_GET_FIRST_DB_ENTRY, 0); 264 if (db_entry != NULL) { 265 gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); 266 if (gnctx->ptr == ptr && gnctx->cookie_num == cookie_num) { 267 268 (void) rw_unlock(&getent_ctxDB_rwlock); 269 (void) rw_wrlock(&getent_ctxDB_rwlock); 270 271 (void) _nscd_delete_db_entry(getent_ctxDB, 272 NSCD_DATA_CTX_ADDR, 273 (const char *)ptrstr, 274 NSCD_DEL_FIRST_DB_ENTRY, 0); 275 } 276 } 277 (void) rw_unlock(&getent_ctxDB_rwlock); 278 } 279 280 static void 281 _nscd_free_getent_ctx( 282 nscd_getent_context_t *gnctx) 283 { 284 285 char *me = "_nscd_free_getent_ctx"; 286 287 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 288 (me, "getent context %p\n", gnctx); 289 290 _nscd_put_nsw_state(gnctx->nsw_state); 291 292 if (gnctx->base != NULL) { 293 /* remove reference to the getent context base */ 294 _nscd_release((nscd_acc_data_t *)gnctx->base); 295 gnctx->base = NULL; 296 } 297 298 _nscd_del_getent_ctx(gnctx, gnctx->cookie_num); 299 free(gnctx); 300 } 301 302 303 static void 304 _nscd_free_getent_ctx_base( 305 nscd_acc_data_t *data) 306 { 307 nscd_getent_ctx_base_t *base = (nscd_getent_ctx_base_t *)data; 308 nscd_getent_context_t *c, *tc; 309 char *me = "_nscd_free_getent_ctx_base"; 310 311 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 312 (me, "getent context base %p\n", base); 313 314 if (base == NULL) 315 return; 316 317 c = base->first; 318 while (c != NULL) { 319 tc = c->next; 320 _nscd_free_getent_ctx(c); 321 c = tc; 322 } 323 } 324 325 void 326 _nscd_free_all_getent_ctx_base() 327 { 328 nscd_getent_ctx_base_t *base; 329 int i; 330 char *me = "_nscd_free_all_getent_ctx_base"; 331 332 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 333 (me, "entering ..\n"); 334 335 (void) rw_wrlock(&nscd_getent_ctx_base_lock); 336 337 for (i = 0; i < NSCD_NUM_DB; i++) { 338 339 base = nscd_getent_ctx_base[i]; 340 if (base == NULL) 341 continue; 342 343 nscd_getent_ctx_base[i] = (nscd_getent_ctx_base_t *) 344 _nscd_set((nscd_acc_data_t *)base, NULL); 345 } 346 (void) rw_unlock(&nscd_getent_ctx_base_lock); 347 } 348 349 static nscd_getent_context_t * 350 _nscd_create_getent_ctx( 351 nscd_nsw_params_t *params) 352 { 353 nscd_getent_context_t *gnctx; 354 nss_db_root_t db_root; 355 char *me = "_nscd_create_getent_ctx"; 356 357 gnctx = calloc(1, sizeof (nscd_getent_context_t)); 358 if (gnctx == NULL) 359 return (NULL); 360 else { 361 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 362 (me, "getent context allocated %p\n", gnctx); 363 } 364 365 gnctx->dbi = params->dbi; 366 gnctx->cookie_num = _nscd_get_cookie_num(); 367 gnctx->pid = -1; 368 (void) mutex_init(&gnctx->getent_mutex, USYNC_THREAD, NULL); 369 370 if (_nscd_get_nsw_state(&db_root, params) != NSCD_SUCCESS) { 371 free(gnctx); 372 return (NULL); 373 } 374 gnctx->nsw_state = (nscd_nsw_state_t *)db_root.s; 375 /* this is a nsw_state used for getent processing */ 376 gnctx->nsw_state->getent = 1; 377 378 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 379 (me, "got nsw_state %p\n", gnctx->nsw_state); 380 381 return (gnctx); 382 } 383 384 385 nscd_rc_t 386 _nscd_get_getent_ctx( 387 nss_getent_t *contextpp, 388 nscd_nsw_params_t *params) 389 { 390 391 nscd_getent_context_t *c; 392 nscd_getent_ctx_base_t *base, *tmp; 393 nscd_rc_t rc; 394 char *me = "_nscd_get_getent_ctx"; 395 396 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 397 (me, "entering ...\n"); 398 399 (void) rw_rdlock(&nscd_getent_ctx_base_lock); 400 base = nscd_getent_ctx_base[params->dbi]; 401 (void) rw_unlock(&nscd_getent_ctx_base_lock); 402 assert(base != NULL); 403 404 /* 405 * If the context list is not empty, return the first one 406 * on the list. Otherwise, create and return a new one if 407 * limit is not reached. if reacehed, wait for the 'one is 408 * available' signal. 409 */ 410 tmp = (nscd_getent_ctx_base_t *)_nscd_mutex_lock( 411 (nscd_acc_data_t *)base); 412 assert(base == tmp); 413 if (base->first == NULL) { 414 if (base->num_getent_ctx == base->max_getent_ctx) { 415 base->num_waiter++; 416 while (base->first == NULL) { 417 418 _NSCD_LOG(NSCD_LOG_GETENT_CTX, 419 NSCD_LOG_LEVEL_DEBUG) 420 (me, "waiting for signal\n"); 421 422 _nscd_cond_wait((nscd_acc_data_t *)base, NULL); 423 424 _NSCD_LOG(NSCD_LOG_GETENT_CTX, 425 NSCD_LOG_LEVEL_DEBUG) 426 (me, "woke up\n"); 427 } 428 base->num_waiter--; 429 } else { 430 base->first = _nscd_create_getent_ctx(params); 431 if (base->first != NULL) 432 base->num_getent_ctx++; 433 else { 434 /* not able to create a getent ctx */ 435 436 _NSCD_LOG(NSCD_LOG_GETENT_CTX, 437 NSCD_LOG_LEVEL_ERROR) 438 (me, "create getent ctx failed\n"); 439 440 _nscd_mutex_unlock((nscd_acc_data_t *)base); 441 return (NSCD_CREATE_GETENT_CTX_FAILED); 442 } 443 444 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 445 (me, "got a new getent ctx %p\n", base->first); 446 } 447 } 448 449 assert(base->first != NULL); 450 451 c = base->first; 452 base->first = c->next; 453 c->next = NULL; 454 c->seq_num = 1; 455 c->cookie_num = _nscd_get_cookie_num(); 456 c->in_use = 1; 457 c->thr_id = thr_self(); 458 459 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 460 (me, "got a getent ctx %p\n", c); 461 462 /* 463 * reference count the getent context base bfore handing out 464 * the getent context 465 */ 466 c->base = (nscd_getent_ctx_base_t *) 467 _nscd_get((nscd_acc_data_t *)base); 468 469 _nscd_mutex_unlock((nscd_acc_data_t *)base); 470 471 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 472 (me, "adding new ctx %p, cookie # = %lld\n", c, c->cookie_num); 473 474 if ((rc = _nscd_add_getent_ctx(c, c->cookie_num)) != NSCD_SUCCESS) { 475 _nscd_put_getent_ctx(c); 476 return (rc); 477 } 478 contextpp->ctx = (struct nss_getent_context *)c; 479 480 /* start monitor and reclaim orphan getent context */ 481 if (getent_monitor_started == 0) { 482 (void) mutex_lock(&getent_monitor_mutex); 483 if (getent_monitor_started == 0) { 484 getent_monitor_started = 1; 485 (void) _nscd_init_getent_ctx_monitor(); 486 } 487 (void) mutex_unlock(&getent_monitor_mutex); 488 } 489 490 return (NSCD_SUCCESS); 491 } 492 493 void 494 _nscd_put_getent_ctx( 495 nscd_getent_context_t *gnctx) 496 { 497 498 nscd_getent_ctx_base_t *base; 499 char *me = "_nscd_put_getent_ctx"; 500 501 base = gnctx->base; 502 503 /* if context base is gone or no longer current, free this context */ 504 if ((_nscd_mutex_lock((nscd_acc_data_t *)base)) == NULL) { 505 _nscd_free_getent_ctx(gnctx); 506 return; 507 } 508 509 if (base->first != NULL) { 510 gnctx->next = base->first; 511 base->first = gnctx; 512 } else 513 base->first = gnctx; 514 515 /* put back the db state */ 516 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 517 (me, "putting back nsw state %p\n", gnctx->nsw_state); 518 519 /* this nsw_state is no longer used for getent processing */ 520 if (gnctx->nsw_state != NULL) { 521 gnctx->nsw_state->getent = 0; 522 _nscd_put_nsw_state(gnctx->nsw_state); 523 gnctx->nsw_state = NULL; 524 } 525 526 gnctx->aborted = 0; 527 gnctx->in_use = 0; 528 gnctx->thr_id = (thread_t)-1; 529 _nscd_del_getent_ctx(gnctx, gnctx->cookie_num); 530 531 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 532 (me, "ctx (%p, cookie # = %lld) removed from getent ctx DB\n", 533 gnctx, gnctx->cookie_num); 534 535 if (base->num_waiter > 0) { 536 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 537 (me, "signaling (waiter = %d)\n", base->num_waiter); 538 539 _nscd_cond_signal((nscd_acc_data_t *)base); 540 } 541 542 gnctx->seq_num = 0; 543 gnctx->cookie_num = 0; 544 gnctx->pid = -1; 545 gnctx->thr_id = (thread_t)-1; 546 gnctx->n_src = 0; 547 gnctx->be = NULL; 548 549 /* remove reference to the getent context base */ 550 _nscd_release((nscd_acc_data_t *)base); 551 gnctx->base = NULL; 552 553 _nscd_mutex_unlock((nscd_acc_data_t *)base); 554 } 555 556 nscd_rc_t 557 _nscd_init_getent_ctx_base( 558 int dbi, 559 int lock) 560 { 561 nscd_getent_ctx_base_t *base = NULL; 562 char *me = "_nscd_init_getent_ctx_base"; 563 564 if (lock) 565 (void) rw_rdlock(&nscd_getent_ctx_base_lock); 566 567 base = (nscd_getent_ctx_base_t *)_nscd_alloc( 568 NSCD_DATA_GETENT_CTX_BASE, 569 sizeof (nscd_getent_ctx_base_t), 570 _nscd_free_getent_ctx_base, 571 NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND); 572 573 if (base == NULL) { 574 if (lock) 575 (void) rw_unlock(&nscd_getent_ctx_base_lock); 576 return (NSCD_NO_MEMORY); 577 } 578 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 579 (me, "base %p allocated\n", base); 580 581 /* 582 * initialize and activate the new getent_ctx base 583 */ 584 base->dbi = dbi; 585 base->max_getent_ctx = NSCD_SW_CFG(dbi).max_getent_ctx_per_db; 586 nscd_getent_ctx_base[dbi] = 587 (nscd_getent_ctx_base_t *)_nscd_set( 588 (nscd_acc_data_t *)nscd_getent_ctx_base[dbi], 589 (nscd_acc_data_t *)base); 590 591 if (lock) 592 (void) rw_unlock(&nscd_getent_ctx_base_lock); 593 594 return (NSCD_SUCCESS); 595 } 596 597 nscd_rc_t 598 _nscd_init_all_getent_ctx_base() 599 { 600 int i; 601 nscd_rc_t rc; 602 char *me = "_nscd_init_all_getent_ctx_base"; 603 604 (void) rw_wrlock(&nscd_getent_ctx_base_lock); 605 606 for (i = 0; i < NSCD_NUM_DB; i++) { 607 608 rc = _nscd_init_getent_ctx_base(i, 0); 609 610 if (rc != NSCD_SUCCESS) { 611 (void) rw_unlock(&nscd_getent_ctx_base_lock); 612 return (rc); 613 } 614 } 615 616 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 617 (me, "all getent context base initialized\n"); 618 619 (void) rw_unlock(&nscd_getent_ctx_base_lock); 620 621 return (NSCD_SUCCESS); 622 } 623 nscd_rc_t 624 _nscd_alloc_getent_ctx_base() 625 { 626 627 (void) rw_wrlock(&nscd_getent_ctx_base_lock); 628 629 nscd_getent_ctx_base = calloc(NSCD_NUM_DB, 630 sizeof (nscd_getent_ctx_base_t *)); 631 if (nscd_getent_ctx_base == NULL) { 632 (void) rw_unlock(&nscd_getent_ctx_base_lock); 633 return (NSCD_NO_MEMORY); 634 } 635 636 (void) rw_unlock(&nscd_getent_ctx_base_lock); 637 638 return (NSCD_SUCCESS); 639 } 640 641 static int 642 process_exited(pid_t pid) 643 { 644 char pname[PATH_MAX]; 645 int fd; 646 647 (void) snprintf(pname, sizeof (pname), "/proc/%d/psinfo", pid); 648 if ((fd = open(pname, O_RDONLY)) == -1) 649 return (1); 650 else { 651 (void) close(fd); 652 return (0); 653 } 654 } 655 656 /* 657 * FUNCTION: reclaim_getent_ctx 658 */ 659 /*ARGSUSED*/ 660 static void * 661 reclaim_getent_ctx(void *arg) 662 { 663 void *cookie = NULL; 664 nscd_db_entry_t *ep; 665 nscd_getent_ctx_t *ctx; 666 nscd_getent_context_t *gctx, *c; 667 nscd_getent_context_t *first = NULL, *last = NULL; 668 nss_getent_t nssctx = { 0 }; 669 char *me = "reclaim_getent_ctx"; 670 671 /*CONSTCOND*/ 672 while (1) { 673 674 (void) sleep(60); 675 676 (void) rw_rdlock(&getent_ctxDB_rwlock); 677 678 for (ep = _nscd_walk_db(getent_ctxDB, &cookie); ep != NULL; 679 ep = _nscd_walk_db(getent_ctxDB, &cookie)) { 680 681 ctx = (nscd_getent_ctx_t *)*(ep->data_array); 682 683 gctx = ctx->ptr; 684 685 /* 686 * if the client process, which did the setent, 687 * exited, add the context to the orphan list 688 */ 689 if (gctx->pid != -1 && process_exited(gctx->pid)) { 690 691 _NSCD_LOG(NSCD_LOG_GETENT_CTX, 692 NSCD_LOG_LEVEL_DEBUG) 693 (me, "process %d exited, " 694 "getent context = %p, " 695 "db index = %d, cookie # = %lld, " 696 "sequence # = %lld\n", 697 gctx->pid, gctx, gctx->dbi, 698 gctx->cookie_num, gctx->seq_num); 699 700 if (first != NULL) { 701 /* add to list if not in already */ 702 for (c = first; c != NULL; 703 c = c->next_to_reclaim) { 704 if (gctx == c) 705 break; 706 } 707 if (c == NULL) { 708 last->next_to_reclaim = gctx; 709 last = gctx; 710 } 711 } else { 712 first = gctx; 713 last = gctx; 714 } 715 } 716 } 717 718 (void) rw_unlock(&getent_ctxDB_rwlock); 719 720 721 /* 722 * return all the orphan getent contexts to the pool if not 723 * in use 724 */ 725 for (gctx = first; gctx; ) { 726 int in_use, num_reclaim_check; 727 728 c = gctx->next_to_reclaim; 729 gctx->next_to_reclaim = NULL; 730 gctx->aborted = 1; 731 732 (void) mutex_lock(&gctx->getent_mutex); 733 num_reclaim_check = gctx->num_reclaim_check++; 734 if (num_reclaim_check > 1) 735 gctx->in_use = 0; 736 in_use = gctx->in_use; 737 (void) mutex_unlock(&gctx->getent_mutex); 738 739 if (in_use == 0) { 740 _NSCD_LOG(NSCD_LOG_GETENT_CTX, 741 NSCD_LOG_LEVEL_DEBUG) 742 (me, "process %d exited, " 743 "freeing getent context = %p\n", 744 gctx->pid, gctx); 745 nssctx.ctx = (struct nss_getent_context *)gctx; 746 nss_endent(NULL, NULL, &nssctx); 747 } 748 gctx = c; 749 } 750 first = last = NULL; 751 } 752 /*NOTREACHED*/ 753 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ 754 } 755 756 static nscd_rc_t 757 _nscd_init_getent_ctx_monitor() { 758 759 int errnum; 760 char *me = "_nscd_init_getent_ctx_monitor"; 761 762 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 763 (me, "initializing the getent context monitor\n"); 764 765 /* 766 * the forker nscd does not process getent requests 767 * so no need to monitor orphan getent contexts 768 */ 769 if (_whoami == NSCD_FORKER) 770 return (NSCD_SUCCESS); 771 772 /* 773 * start a thread to reclaim unused getent contexts 774 */ 775 if (thr_create(NULL, NULL, reclaim_getent_ctx, 776 NULL, THR_DETACHED, NULL) != 0) { 777 errnum = errno; 778 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_ERROR) 779 (me, "thr_create: %s\n", strerror(errnum)); 780 return (NSCD_THREAD_CREATE_ERROR); 781 } 782 783 return (NSCD_SUCCESS); 784 } 785