1cb5caa98Sdjl /* 2cb5caa98Sdjl * CDDL HEADER START 3cb5caa98Sdjl * 4cb5caa98Sdjl * The contents of this file are subject to the terms of the 5cb5caa98Sdjl * Common Development and Distribution License (the "License"). 6cb5caa98Sdjl * You may not use this file except in compliance with the License. 7cb5caa98Sdjl * 8cb5caa98Sdjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9cb5caa98Sdjl * or http://www.opensolaris.org/os/licensing. 10cb5caa98Sdjl * See the License for the specific language governing permissions 11cb5caa98Sdjl * and limitations under the License. 12cb5caa98Sdjl * 13cb5caa98Sdjl * When distributing Covered Code, include this CDDL HEADER in each 14cb5caa98Sdjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15cb5caa98Sdjl * If applicable, add the following below this CDDL HEADER, with the 16cb5caa98Sdjl * fields enclosed by brackets "[]" replaced with your own identifying 17cb5caa98Sdjl * information: Portions Copyright [yyyy] [name of copyright owner] 18cb5caa98Sdjl * 19cb5caa98Sdjl * CDDL HEADER END 20cb5caa98Sdjl */ 21cb5caa98Sdjl /* 22*cfed26cbSMichen Chang * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23cb5caa98Sdjl * Use is subject to license terms. 24cb5caa98Sdjl */ 25cb5caa98Sdjl 26cb5caa98Sdjl #include <stdlib.h> 27cb5caa98Sdjl #include <assert.h> 28cb5caa98Sdjl #include <string.h> 29cb5caa98Sdjl #include <errno.h> 30cb5caa98Sdjl #include <fcntl.h> 31cb5caa98Sdjl #include "nscd_db.h" 32cb5caa98Sdjl #include "nscd_log.h" 33cb5caa98Sdjl #include "nscd_switch.h" 34cb5caa98Sdjl #include "nscd_door.h" 35cb5caa98Sdjl 36cb5caa98Sdjl extern int _whoami; 37cb5caa98Sdjl static mutex_t getent_monitor_mutex = DEFAULTMUTEX; 38cb5caa98Sdjl static int getent_monitor_started = 0; 39cb5caa98Sdjl 40cb5caa98Sdjl static rwlock_t getent_ctxDB_rwlock = DEFAULTRWLOCK; 41cb5caa98Sdjl static nscd_db_t *getent_ctxDB = NULL; 42cb5caa98Sdjl 43cb5caa98Sdjl /* 44cb5caa98Sdjl * internal structure representing a nscd getent context 45cb5caa98Sdjl */ 46cb5caa98Sdjl typedef struct nscd_getent_ctx { 47cb5caa98Sdjl int to_delete; /* this ctx no longer valid */ 48cb5caa98Sdjl nscd_getent_context_t *ptr; 49e37190e5Smichen nscd_cookie_num_t cookie_num; 50cb5caa98Sdjl } nscd_getent_ctx_t; 51cb5caa98Sdjl 52cb5caa98Sdjl /* 53cb5caa98Sdjl * nscd_getent_context_t list for each nss database. Protected 54cb5caa98Sdjl * by the readers/writer lock nscd_getent_ctx_lock. 55cb5caa98Sdjl */ 56cb5caa98Sdjl nscd_getent_ctx_base_t **nscd_getent_ctx_base; 57cb5caa98Sdjl static rwlock_t nscd_getent_ctx_base_lock = DEFAULTRWLOCK; 58cb5caa98Sdjl 59cb5caa98Sdjl extern nscd_db_entry_t *_nscd_walk_db(nscd_db_t *db, void **cookie); 60cb5caa98Sdjl 61cb5caa98Sdjl static nscd_rc_t _nscd_init_getent_ctx_monitor(); 62cb5caa98Sdjl 63cb5caa98Sdjl /* 64cb5caa98Sdjl * FUNCTION: _nscd_create_getent_ctxDB 65cb5caa98Sdjl * 66cb5caa98Sdjl * Create the internal getent context database to keep track of the 67cb5caa98Sdjl * getent contexts currently being used. 68cb5caa98Sdjl */ 69cb5caa98Sdjl nscd_db_t * 70cb5caa98Sdjl _nscd_create_getent_ctxDB() 71cb5caa98Sdjl { 72cb5caa98Sdjl 73cb5caa98Sdjl nscd_db_t *ret; 74cb5caa98Sdjl 75cb5caa98Sdjl (void) rw_wrlock(&getent_ctxDB_rwlock); 76cb5caa98Sdjl 77cb5caa98Sdjl if (getent_ctxDB != NULL) { 78cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 79cb5caa98Sdjl return (getent_ctxDB); 80cb5caa98Sdjl } 81cb5caa98Sdjl 82cb5caa98Sdjl ret = _nscd_alloc_db(NSCD_DB_SIZE_LARGE); 83cb5caa98Sdjl 84cb5caa98Sdjl if (ret != NULL) 85cb5caa98Sdjl getent_ctxDB = ret; 86cb5caa98Sdjl 87cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 88cb5caa98Sdjl 89cb5caa98Sdjl return (ret); 90cb5caa98Sdjl } 91cb5caa98Sdjl 92cb5caa98Sdjl /* 93cb5caa98Sdjl * FUNCTION: _nscd_add_getent_ctx 94cb5caa98Sdjl * 95cb5caa98Sdjl * Add a getent context to the internal context database. 96cb5caa98Sdjl */ 97cb5caa98Sdjl static nscd_rc_t 98cb5caa98Sdjl _nscd_add_getent_ctx( 99cb5caa98Sdjl nscd_getent_context_t *ptr, 100e37190e5Smichen nscd_cookie_num_t cookie_num) 101cb5caa98Sdjl { 102cb5caa98Sdjl int size; 10329836b19Smichen char buf[32]; 104cb5caa98Sdjl nscd_db_entry_t *db_entry; 105cb5caa98Sdjl nscd_getent_ctx_t *gnctx; 106cb5caa98Sdjl 107cb5caa98Sdjl if (ptr == NULL) 108cb5caa98Sdjl return (NSCD_INVALID_ARGUMENT); 109cb5caa98Sdjl 110e37190e5Smichen (void) snprintf(buf, sizeof (buf), "%lld", cookie_num); 111cb5caa98Sdjl 112cb5caa98Sdjl size = sizeof (*gnctx); 113cb5caa98Sdjl 114cb5caa98Sdjl db_entry = _nscd_alloc_db_entry(NSCD_DATA_CTX_ADDR, 115cb5caa98Sdjl (const char *)buf, size, 1, 1); 116cb5caa98Sdjl if (db_entry == NULL) 117cb5caa98Sdjl return (NSCD_NO_MEMORY); 118cb5caa98Sdjl 119cb5caa98Sdjl gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); 120cb5caa98Sdjl gnctx->ptr = ptr; 121e37190e5Smichen gnctx->cookie_num = cookie_num; 122cb5caa98Sdjl 123cb5caa98Sdjl (void) rw_wrlock(&getent_ctxDB_rwlock); 124cb5caa98Sdjl (void) _nscd_add_db_entry(getent_ctxDB, buf, db_entry, 125cb5caa98Sdjl NSCD_ADD_DB_ENTRY_FIRST); 126cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 127cb5caa98Sdjl 128cb5caa98Sdjl return (NSCD_SUCCESS); 129cb5caa98Sdjl } 130cb5caa98Sdjl 131cb5caa98Sdjl /* 132cb5caa98Sdjl * FUNCTION: _nscd_is_getent_ctx 133cb5caa98Sdjl * 134cb5caa98Sdjl * Check to see if a getent context can be found in the internal 135cb5caa98Sdjl * getent context database. 136cb5caa98Sdjl */ 137cb5caa98Sdjl nscd_getent_context_t * 138cb5caa98Sdjl _nscd_is_getent_ctx( 139e37190e5Smichen nscd_cookie_num_t cookie_num) 140cb5caa98Sdjl { 14129836b19Smichen char ptrstr[32]; 142cb5caa98Sdjl const nscd_db_entry_t *db_entry; 143cb5caa98Sdjl nscd_getent_context_t *ret = NULL; 1446392794bSMichen Chang char *me = "_nscd_is_getent_ctx"; 145cb5caa98Sdjl 146e37190e5Smichen (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num); 147cb5caa98Sdjl 148cb5caa98Sdjl (void) rw_rdlock(&getent_ctxDB_rwlock); 149cb5caa98Sdjl 150cb5caa98Sdjl db_entry = _nscd_get_db_entry(getent_ctxDB, NSCD_DATA_CTX_ADDR, 151cb5caa98Sdjl (const char *)ptrstr, NSCD_GET_FIRST_DB_ENTRY, 0); 152cb5caa98Sdjl 153cb5caa98Sdjl if (db_entry != NULL) { 154cb5caa98Sdjl nscd_getent_ctx_t *gnctx; 155cb5caa98Sdjl 156cb5caa98Sdjl gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); 1576392794bSMichen Chang _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 1586392794bSMichen Chang (me, "getent context %p, cookie# %lld, to_delete %d\n", 1596392794bSMichen Chang gnctx->ptr, gnctx->cookie_num, gnctx->to_delete); 160cb5caa98Sdjl 161cb5caa98Sdjl /* 1626392794bSMichen Chang * If the ctx is not to be deleted and the cookie numbers 163*cfed26cbSMichen Chang * match, return the ctx if not aborted and not in use. 164cb5caa98Sdjl * Otherwise return NULL. 165cb5caa98Sdjl */ 16629836b19Smichen if (gnctx->to_delete == 0 && gnctx->cookie_num == cookie_num) { 167cb5caa98Sdjl ret = gnctx->ptr; 16829836b19Smichen (void) mutex_lock(&gnctx->ptr->getent_mutex); 16929836b19Smichen if (ret->aborted == 1 || ret->in_use == 1) 17029836b19Smichen ret = NULL; 17129836b19Smichen else 17229836b19Smichen ret->in_use = 1; 17329836b19Smichen (void) mutex_unlock(&gnctx->ptr->getent_mutex); 17429836b19Smichen } 175cb5caa98Sdjl } 176cb5caa98Sdjl 177cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 178cb5caa98Sdjl 179cb5caa98Sdjl return (ret); 180cb5caa98Sdjl } 181cb5caa98Sdjl 1826392794bSMichen Chang int 1836392794bSMichen Chang _nscd_is_getent_ctx_in_use( 1846392794bSMichen Chang nscd_getent_context_t *ctx) 1856392794bSMichen Chang { 1866392794bSMichen Chang int in_use; 1876392794bSMichen Chang char *me = "_nscd_getent_ctx_in_use"; 1886392794bSMichen Chang 1896392794bSMichen Chang (void) mutex_lock(&ctx->getent_mutex); 1906392794bSMichen Chang 1916392794bSMichen Chang _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 1926392794bSMichen Chang (me, "in_use = %d, ctx->thr_id = %d, thread id = %d\n", 1936392794bSMichen Chang ctx->in_use, ctx->thr_id, thr_self()); 1946392794bSMichen Chang 1956392794bSMichen Chang in_use = ctx->in_use; 1966392794bSMichen Chang if (in_use == 1 && ctx->thr_id == thr_self()) 1976392794bSMichen Chang in_use = 0; 1986392794bSMichen Chang (void) mutex_unlock(&ctx->getent_mutex); 1996392794bSMichen Chang return (in_use); 2006392794bSMichen Chang } 2016392794bSMichen Chang 202cb5caa98Sdjl /* 20329836b19Smichen * FUNCTION: _nscd_free_ctx_if_aborted 20429836b19Smichen * 20529836b19Smichen * Check to see if the getent session associated with a getent context had 20629836b19Smichen * been aborted. If so, return the getent context back to the pool. 20729836b19Smichen */ 20829836b19Smichen void 20929836b19Smichen _nscd_free_ctx_if_aborted( 21029836b19Smichen nscd_getent_context_t *ctx) 21129836b19Smichen { 21229836b19Smichen int aborted; 21329836b19Smichen char *me = "_nscd_free_ctx_if_aborted"; 21429836b19Smichen 21529836b19Smichen (void) mutex_lock(&ctx->getent_mutex); 2166392794bSMichen Chang 2176392794bSMichen Chang _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 2186392794bSMichen Chang (me, "in_use = %d, aborted = %d\n", ctx->in_use, ctx->aborted); 2196392794bSMichen Chang 2206392794bSMichen Chang if (ctx->in_use != 1) { 2216392794bSMichen Chang (void) mutex_unlock(&ctx->getent_mutex); 2226392794bSMichen Chang return; 2236392794bSMichen Chang } 22429836b19Smichen aborted = ctx->aborted; 2256392794bSMichen Chang ctx->in_use = 0; 22629836b19Smichen (void) mutex_unlock(&ctx->getent_mutex); 22729836b19Smichen 22829836b19Smichen if (aborted == 1) { 22929836b19Smichen _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 23029836b19Smichen (me, "getent session aborted, return the getent context\n"); 23129836b19Smichen _nscd_put_getent_ctx(ctx); 23229836b19Smichen } 23329836b19Smichen } 23429836b19Smichen 23529836b19Smichen /* 236cb5caa98Sdjl * FUNCTION: _nscd_del_getent_ctx 237cb5caa98Sdjl * 238cb5caa98Sdjl * Delete a getent context from the internal getent context database. 239cb5caa98Sdjl */ 240cb5caa98Sdjl static void 241cb5caa98Sdjl _nscd_del_getent_ctx( 242cb5caa98Sdjl nscd_getent_context_t *ptr, 243e37190e5Smichen nscd_cookie_num_t cookie_num) 244cb5caa98Sdjl { 24529836b19Smichen char ptrstr[32]; 246cb5caa98Sdjl nscd_getent_ctx_t *gnctx; 247cb5caa98Sdjl const nscd_db_entry_t *db_entry; 248cb5caa98Sdjl 249cb5caa98Sdjl if (ptr == NULL) 250cb5caa98Sdjl return; 251cb5caa98Sdjl 252e37190e5Smichen (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num); 253cb5caa98Sdjl 254cb5caa98Sdjl (void) rw_rdlock(&getent_ctxDB_rwlock); 255cb5caa98Sdjl /* 256cb5caa98Sdjl * first find the db entry and make sure the 257cb5caa98Sdjl * sequence number matched, then delete it from 258cb5caa98Sdjl * the database. 259cb5caa98Sdjl */ 260cb5caa98Sdjl db_entry = _nscd_get_db_entry(getent_ctxDB, 261cb5caa98Sdjl NSCD_DATA_CTX_ADDR, 262cb5caa98Sdjl (const char *)ptrstr, 263cb5caa98Sdjl NSCD_GET_FIRST_DB_ENTRY, 0); 264cb5caa98Sdjl if (db_entry != NULL) { 265cb5caa98Sdjl gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); 266e37190e5Smichen if (gnctx->ptr == ptr && gnctx->cookie_num == cookie_num) { 267cb5caa98Sdjl 268cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 269cb5caa98Sdjl (void) rw_wrlock(&getent_ctxDB_rwlock); 270cb5caa98Sdjl 271cb5caa98Sdjl (void) _nscd_delete_db_entry(getent_ctxDB, 272cb5caa98Sdjl NSCD_DATA_CTX_ADDR, 273cb5caa98Sdjl (const char *)ptrstr, 274cb5caa98Sdjl NSCD_DEL_FIRST_DB_ENTRY, 0); 275cb5caa98Sdjl } 276cb5caa98Sdjl } 277cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 278cb5caa98Sdjl } 279cb5caa98Sdjl 280cb5caa98Sdjl static void 281cb5caa98Sdjl _nscd_free_getent_ctx( 282cb5caa98Sdjl nscd_getent_context_t *gnctx) 283cb5caa98Sdjl { 284cb5caa98Sdjl 285cb5caa98Sdjl char *me = "_nscd_free_getent_ctx"; 286cb5caa98Sdjl 287cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 288cb5caa98Sdjl (me, "getent context %p\n", gnctx); 289cb5caa98Sdjl 290cb5caa98Sdjl _nscd_put_nsw_state(gnctx->nsw_state); 291*cfed26cbSMichen Chang 292*cfed26cbSMichen Chang if (gnctx->base != NULL) { 293*cfed26cbSMichen Chang /* remove reference to the getent context base */ 294*cfed26cbSMichen Chang _nscd_release((nscd_acc_data_t *)gnctx->base); 295*cfed26cbSMichen Chang gnctx->base = NULL; 296*cfed26cbSMichen Chang } 297*cfed26cbSMichen Chang 298e37190e5Smichen _nscd_del_getent_ctx(gnctx, gnctx->cookie_num); 299cb5caa98Sdjl free(gnctx); 300cb5caa98Sdjl } 301cb5caa98Sdjl 302cb5caa98Sdjl 303cb5caa98Sdjl static void 304cb5caa98Sdjl _nscd_free_getent_ctx_base( 305cb5caa98Sdjl nscd_acc_data_t *data) 306cb5caa98Sdjl { 307cb5caa98Sdjl nscd_getent_ctx_base_t *base = (nscd_getent_ctx_base_t *)data; 308cb5caa98Sdjl nscd_getent_context_t *c, *tc; 309cb5caa98Sdjl char *me = "_nscd_free_getent_ctx_base"; 310cb5caa98Sdjl 311cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 312cb5caa98Sdjl (me, "getent context base %p\n", base); 313cb5caa98Sdjl 314cb5caa98Sdjl if (base == NULL) 315cb5caa98Sdjl return; 316cb5caa98Sdjl 317cb5caa98Sdjl c = base->first; 318cb5caa98Sdjl while (c != NULL) { 319cb5caa98Sdjl tc = c->next; 320cb5caa98Sdjl _nscd_free_getent_ctx(c); 321cb5caa98Sdjl c = tc; 322cb5caa98Sdjl } 323cb5caa98Sdjl } 324cb5caa98Sdjl 325cb5caa98Sdjl void 326cb5caa98Sdjl _nscd_free_all_getent_ctx_base() 327cb5caa98Sdjl { 328cb5caa98Sdjl nscd_getent_ctx_base_t *base; 329cb5caa98Sdjl int i; 330cb5caa98Sdjl char *me = "_nscd_free_all_getent_ctx_base"; 331cb5caa98Sdjl 332cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 333cb5caa98Sdjl (me, "entering ..\n"); 334cb5caa98Sdjl 335cb5caa98Sdjl (void) rw_wrlock(&nscd_getent_ctx_base_lock); 336cb5caa98Sdjl 337cb5caa98Sdjl for (i = 0; i < NSCD_NUM_DB; i++) { 338cb5caa98Sdjl 339cb5caa98Sdjl base = nscd_getent_ctx_base[i]; 340cb5caa98Sdjl if (base == NULL) 341cb5caa98Sdjl continue; 342cb5caa98Sdjl 343cb5caa98Sdjl nscd_getent_ctx_base[i] = (nscd_getent_ctx_base_t *) 344cb5caa98Sdjl _nscd_set((nscd_acc_data_t *)base, NULL); 345cb5caa98Sdjl } 346cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 347cb5caa98Sdjl } 348cb5caa98Sdjl 349cb5caa98Sdjl static nscd_getent_context_t * 350cb5caa98Sdjl _nscd_create_getent_ctx( 351cb5caa98Sdjl nscd_nsw_params_t *params) 352cb5caa98Sdjl { 353cb5caa98Sdjl nscd_getent_context_t *gnctx; 354cb5caa98Sdjl nss_db_root_t db_root; 355cb5caa98Sdjl char *me = "_nscd_create_getent_ctx"; 356cb5caa98Sdjl 357cb5caa98Sdjl gnctx = calloc(1, sizeof (nscd_getent_context_t)); 358cb5caa98Sdjl if (gnctx == NULL) 359cb5caa98Sdjl return (NULL); 360cb5caa98Sdjl else { 361cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 362cb5caa98Sdjl (me, "getent context allocated %p\n", gnctx); 363cb5caa98Sdjl } 364cb5caa98Sdjl 365cb5caa98Sdjl gnctx->dbi = params->dbi; 366e37190e5Smichen gnctx->cookie_num = _nscd_get_cookie_num(); 3679f590749Smichen gnctx->pid = -1; 36829836b19Smichen (void) mutex_init(&gnctx->getent_mutex, USYNC_THREAD, NULL); 369cb5caa98Sdjl 370cb5caa98Sdjl if (_nscd_get_nsw_state(&db_root, params) != NSCD_SUCCESS) { 371cb5caa98Sdjl free(gnctx); 372cb5caa98Sdjl return (NULL); 373cb5caa98Sdjl } 374cb5caa98Sdjl gnctx->nsw_state = (nscd_nsw_state_t *)db_root.s; 375cb5caa98Sdjl /* this is a nsw_state used for getent processing */ 376cb5caa98Sdjl gnctx->nsw_state->getent = 1; 377cb5caa98Sdjl 378cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 379cb5caa98Sdjl (me, "got nsw_state %p\n", gnctx->nsw_state); 380cb5caa98Sdjl 381cb5caa98Sdjl return (gnctx); 382cb5caa98Sdjl } 383cb5caa98Sdjl 384cb5caa98Sdjl 385cb5caa98Sdjl nscd_rc_t 386cb5caa98Sdjl _nscd_get_getent_ctx( 387cb5caa98Sdjl nss_getent_t *contextpp, 388cb5caa98Sdjl nscd_nsw_params_t *params) 389cb5caa98Sdjl { 390cb5caa98Sdjl 391cb5caa98Sdjl nscd_getent_context_t *c; 392cb5caa98Sdjl nscd_getent_ctx_base_t *base, *tmp; 393cb5caa98Sdjl nscd_rc_t rc; 394cb5caa98Sdjl char *me = "_nscd_get_getent_ctx"; 395cb5caa98Sdjl 396cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 397cb5caa98Sdjl (me, "entering ...\n"); 398cb5caa98Sdjl 399cb5caa98Sdjl (void) rw_rdlock(&nscd_getent_ctx_base_lock); 400cb5caa98Sdjl base = nscd_getent_ctx_base[params->dbi]; 401cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 402cb5caa98Sdjl assert(base != NULL); 403cb5caa98Sdjl 404cb5caa98Sdjl /* 405cb5caa98Sdjl * If the context list is not empty, return the first one 406cb5caa98Sdjl * on the list. Otherwise, create and return a new one if 407cb5caa98Sdjl * limit is not reached. if reacehed, wait for the 'one is 408cb5caa98Sdjl * available' signal. 409cb5caa98Sdjl */ 410cb5caa98Sdjl tmp = (nscd_getent_ctx_base_t *)_nscd_mutex_lock( 411cb5caa98Sdjl (nscd_acc_data_t *)base); 412cb5caa98Sdjl assert(base == tmp); 413cb5caa98Sdjl if (base->first == NULL) { 414cb5caa98Sdjl if (base->num_getent_ctx == base->max_getent_ctx) { 415cb5caa98Sdjl base->num_waiter++; 416cb5caa98Sdjl while (base->first == NULL) { 417cb5caa98Sdjl 418cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, 419cb5caa98Sdjl NSCD_LOG_LEVEL_DEBUG) 420cb5caa98Sdjl (me, "waiting for signal\n"); 421cb5caa98Sdjl 422cb5caa98Sdjl _nscd_cond_wait((nscd_acc_data_t *)base, NULL); 423cb5caa98Sdjl 424cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, 425cb5caa98Sdjl NSCD_LOG_LEVEL_DEBUG) 426cb5caa98Sdjl (me, "woke up\n"); 427cb5caa98Sdjl } 428cb5caa98Sdjl base->num_waiter--; 429cb5caa98Sdjl } else { 430cb5caa98Sdjl base->first = _nscd_create_getent_ctx(params); 431*cfed26cbSMichen Chang if (base->first != NULL) 432cb5caa98Sdjl base->num_getent_ctx++; 433*cfed26cbSMichen Chang else { 434*cfed26cbSMichen Chang /* not able to create a getent ctx */ 435cb5caa98Sdjl 436cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, 437cb5caa98Sdjl NSCD_LOG_LEVEL_ERROR) 438cb5caa98Sdjl (me, "create getent ctx failed\n"); 439cb5caa98Sdjl 440cb5caa98Sdjl _nscd_mutex_unlock((nscd_acc_data_t *)base); 441cb5caa98Sdjl return (NSCD_CREATE_GETENT_CTX_FAILED); 442cb5caa98Sdjl } 443cb5caa98Sdjl 444cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 445cb5caa98Sdjl (me, "got a new getent ctx %p\n", base->first); 446cb5caa98Sdjl } 447cb5caa98Sdjl } 448cb5caa98Sdjl 449cb5caa98Sdjl assert(base->first != NULL); 450cb5caa98Sdjl 451cb5caa98Sdjl c = base->first; 452cb5caa98Sdjl base->first = c->next; 453cb5caa98Sdjl c->next = NULL; 454cb5caa98Sdjl c->seq_num = 1; 4556392794bSMichen Chang c->cookie_num = _nscd_get_cookie_num(); 45629836b19Smichen c->in_use = 1; 4576392794bSMichen Chang c->thr_id = thr_self(); 458cb5caa98Sdjl 459cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 460cb5caa98Sdjl (me, "got a getent ctx %p\n", c); 461cb5caa98Sdjl 462*cfed26cbSMichen Chang /* 463*cfed26cbSMichen Chang * reference count the getent context base bfore handing out 464*cfed26cbSMichen Chang * the getent context 465*cfed26cbSMichen Chang */ 466*cfed26cbSMichen Chang c->base = (nscd_getent_ctx_base_t *) 467*cfed26cbSMichen Chang _nscd_get((nscd_acc_data_t *)base); 468*cfed26cbSMichen Chang 469cb5caa98Sdjl _nscd_mutex_unlock((nscd_acc_data_t *)base); 470cb5caa98Sdjl 471cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 472e37190e5Smichen (me, "adding new ctx %p, cookie # = %lld\n", c, c->cookie_num); 473cb5caa98Sdjl 474e37190e5Smichen if ((rc = _nscd_add_getent_ctx(c, c->cookie_num)) != NSCD_SUCCESS) { 475cb5caa98Sdjl _nscd_put_getent_ctx(c); 476cb5caa98Sdjl return (rc); 477cb5caa98Sdjl } 478cb5caa98Sdjl contextpp->ctx = (struct nss_getent_context *)c; 479cb5caa98Sdjl 480cb5caa98Sdjl /* start monitor and reclaim orphan getent context */ 481cb5caa98Sdjl if (getent_monitor_started == 0) { 482cb5caa98Sdjl (void) mutex_lock(&getent_monitor_mutex); 483cb5caa98Sdjl if (getent_monitor_started == 0) { 484cb5caa98Sdjl getent_monitor_started = 1; 485cb5caa98Sdjl (void) _nscd_init_getent_ctx_monitor(); 486cb5caa98Sdjl } 487cb5caa98Sdjl (void) mutex_unlock(&getent_monitor_mutex); 488cb5caa98Sdjl } 489cb5caa98Sdjl 490cb5caa98Sdjl return (NSCD_SUCCESS); 491cb5caa98Sdjl } 492cb5caa98Sdjl 493cb5caa98Sdjl void 494cb5caa98Sdjl _nscd_put_getent_ctx( 495cb5caa98Sdjl nscd_getent_context_t *gnctx) 496cb5caa98Sdjl { 497cb5caa98Sdjl 498cb5caa98Sdjl nscd_getent_ctx_base_t *base; 499cb5caa98Sdjl char *me = "_nscd_put_getent_ctx"; 500cb5caa98Sdjl 501cb5caa98Sdjl base = gnctx->base; 502cb5caa98Sdjl 503*cfed26cbSMichen Chang /* if context base is gone or no longer current, free this context */ 504cb5caa98Sdjl if ((_nscd_mutex_lock((nscd_acc_data_t *)base)) == NULL) { 505cb5caa98Sdjl _nscd_free_getent_ctx(gnctx); 506cb5caa98Sdjl return; 507cb5caa98Sdjl } 508cb5caa98Sdjl 509cb5caa98Sdjl if (base->first != NULL) { 510cb5caa98Sdjl gnctx->next = base->first; 511cb5caa98Sdjl base->first = gnctx; 512cb5caa98Sdjl } else 513cb5caa98Sdjl base->first = gnctx; 514cb5caa98Sdjl 515cb5caa98Sdjl /* put back the db state */ 516cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 517cb5caa98Sdjl (me, "putting back nsw state %p\n", gnctx->nsw_state); 518cb5caa98Sdjl 519cb5caa98Sdjl /* this nsw_state is no longer used for getent processing */ 5206392794bSMichen Chang if (gnctx->nsw_state != NULL) { 521cb5caa98Sdjl gnctx->nsw_state->getent = 0; 522cb5caa98Sdjl _nscd_put_nsw_state(gnctx->nsw_state); 523cb5caa98Sdjl gnctx->nsw_state = NULL; 5246392794bSMichen Chang } 525cb5caa98Sdjl 52629836b19Smichen gnctx->aborted = 0; 52729836b19Smichen gnctx->in_use = 0; 5286392794bSMichen Chang gnctx->thr_id = (thread_t)-1; 529e37190e5Smichen _nscd_del_getent_ctx(gnctx, gnctx->cookie_num); 530cb5caa98Sdjl 531cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 532e37190e5Smichen (me, "ctx (%p, cookie # = %lld) removed from getent ctx DB\n", 533e37190e5Smichen gnctx, gnctx->cookie_num); 534cb5caa98Sdjl 535cb5caa98Sdjl if (base->num_waiter > 0) { 536cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 537cb5caa98Sdjl (me, "signaling (waiter = %d)\n", base->num_waiter); 538cb5caa98Sdjl 539cb5caa98Sdjl _nscd_cond_signal((nscd_acc_data_t *)base); 540cb5caa98Sdjl } 541cb5caa98Sdjl 5426392794bSMichen Chang gnctx->seq_num = 0; 5436392794bSMichen Chang gnctx->cookie_num = 0; 5446392794bSMichen Chang gnctx->pid = -1; 5456392794bSMichen Chang gnctx->thr_id = (thread_t)-1; 5466392794bSMichen Chang gnctx->n_src = 0; 5476392794bSMichen Chang gnctx->be = NULL; 5486392794bSMichen Chang 549*cfed26cbSMichen Chang /* remove reference to the getent context base */ 550*cfed26cbSMichen Chang _nscd_release((nscd_acc_data_t *)base); 551*cfed26cbSMichen Chang gnctx->base = NULL; 552*cfed26cbSMichen Chang 553cb5caa98Sdjl _nscd_mutex_unlock((nscd_acc_data_t *)base); 554cb5caa98Sdjl } 555cb5caa98Sdjl 556cb5caa98Sdjl nscd_rc_t 557cb5caa98Sdjl _nscd_init_getent_ctx_base( 558cb5caa98Sdjl int dbi, 559cb5caa98Sdjl int lock) 560cb5caa98Sdjl { 561cb5caa98Sdjl nscd_getent_ctx_base_t *base = NULL; 562cb5caa98Sdjl char *me = "_nscd_init_getent_ctx_base"; 563cb5caa98Sdjl 564cb5caa98Sdjl if (lock) 565cb5caa98Sdjl (void) rw_rdlock(&nscd_getent_ctx_base_lock); 566cb5caa98Sdjl 567cb5caa98Sdjl base = (nscd_getent_ctx_base_t *)_nscd_alloc( 568cb5caa98Sdjl NSCD_DATA_GETENT_CTX_BASE, 569cb5caa98Sdjl sizeof (nscd_getent_ctx_base_t), 570cb5caa98Sdjl _nscd_free_getent_ctx_base, 571cb5caa98Sdjl NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND); 572cb5caa98Sdjl 573cb5caa98Sdjl if (base == NULL) { 574cb5caa98Sdjl if (lock) 575cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 576cb5caa98Sdjl return (NSCD_NO_MEMORY); 577cb5caa98Sdjl } 578cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 579cb5caa98Sdjl (me, "base %p allocated\n", base); 580cb5caa98Sdjl 581cb5caa98Sdjl /* 582cb5caa98Sdjl * initialize and activate the new getent_ctx base 583cb5caa98Sdjl */ 584cb5caa98Sdjl base->dbi = dbi; 585cb5caa98Sdjl base->max_getent_ctx = NSCD_SW_CFG(dbi).max_getent_ctx_per_db; 586cb5caa98Sdjl nscd_getent_ctx_base[dbi] = 587cb5caa98Sdjl (nscd_getent_ctx_base_t *)_nscd_set( 588cb5caa98Sdjl (nscd_acc_data_t *)nscd_getent_ctx_base[dbi], 589cb5caa98Sdjl (nscd_acc_data_t *)base); 590cb5caa98Sdjl 591cb5caa98Sdjl if (lock) 592cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 593cb5caa98Sdjl 594cb5caa98Sdjl return (NSCD_SUCCESS); 595cb5caa98Sdjl } 596cb5caa98Sdjl 597cb5caa98Sdjl nscd_rc_t 598cb5caa98Sdjl _nscd_init_all_getent_ctx_base() 599cb5caa98Sdjl { 600cb5caa98Sdjl int i; 601cb5caa98Sdjl nscd_rc_t rc; 602cb5caa98Sdjl char *me = "_nscd_init_all_getent_ctx_base"; 603cb5caa98Sdjl 604cb5caa98Sdjl (void) rw_wrlock(&nscd_getent_ctx_base_lock); 605cb5caa98Sdjl 606cb5caa98Sdjl for (i = 0; i < NSCD_NUM_DB; i++) { 607cb5caa98Sdjl 608cb5caa98Sdjl rc = _nscd_init_getent_ctx_base(i, 0); 609cb5caa98Sdjl 610cb5caa98Sdjl if (rc != NSCD_SUCCESS) { 611cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 612cb5caa98Sdjl return (rc); 613cb5caa98Sdjl } 614cb5caa98Sdjl } 615cb5caa98Sdjl 616cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 617cb5caa98Sdjl (me, "all getent context base initialized\n"); 618cb5caa98Sdjl 619cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 620cb5caa98Sdjl 621cb5caa98Sdjl return (NSCD_SUCCESS); 622cb5caa98Sdjl } 623cb5caa98Sdjl nscd_rc_t 624cb5caa98Sdjl _nscd_alloc_getent_ctx_base() 625cb5caa98Sdjl { 626cb5caa98Sdjl 627cb5caa98Sdjl (void) rw_wrlock(&nscd_getent_ctx_base_lock); 628cb5caa98Sdjl 629cb5caa98Sdjl nscd_getent_ctx_base = calloc(NSCD_NUM_DB, 630cb5caa98Sdjl sizeof (nscd_getent_ctx_base_t *)); 631cb5caa98Sdjl if (nscd_getent_ctx_base == NULL) { 632cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 633cb5caa98Sdjl return (NSCD_NO_MEMORY); 634cb5caa98Sdjl } 635cb5caa98Sdjl 636cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 637cb5caa98Sdjl 638cb5caa98Sdjl return (NSCD_SUCCESS); 639cb5caa98Sdjl } 640cb5caa98Sdjl 641cb5caa98Sdjl static int 642cb5caa98Sdjl process_exited(pid_t pid) 643cb5caa98Sdjl { 644cb5caa98Sdjl char pname[PATH_MAX]; 645cb5caa98Sdjl int fd; 646cb5caa98Sdjl 647cb5caa98Sdjl (void) snprintf(pname, sizeof (pname), "/proc/%d/psinfo", pid); 648cb5caa98Sdjl if ((fd = open(pname, O_RDONLY)) == -1) 649cb5caa98Sdjl return (1); 650cb5caa98Sdjl else { 651cb5caa98Sdjl (void) close(fd); 652cb5caa98Sdjl return (0); 653cb5caa98Sdjl } 654cb5caa98Sdjl } 655cb5caa98Sdjl 656cb5caa98Sdjl /* 657cb5caa98Sdjl * FUNCTION: reclaim_getent_ctx 658cb5caa98Sdjl */ 659cb5caa98Sdjl /*ARGSUSED*/ 660cb5caa98Sdjl static void * 661cb5caa98Sdjl reclaim_getent_ctx(void *arg) 662cb5caa98Sdjl { 663cb5caa98Sdjl void *cookie = NULL; 664cb5caa98Sdjl nscd_db_entry_t *ep; 665cb5caa98Sdjl nscd_getent_ctx_t *ctx; 666cb5caa98Sdjl nscd_getent_context_t *gctx, *c; 667cb5caa98Sdjl nscd_getent_context_t *first = NULL, *last = NULL; 6686392794bSMichen Chang nss_getent_t nssctx = { 0 }; 669cb5caa98Sdjl char *me = "reclaim_getent_ctx"; 670cb5caa98Sdjl 671cb5caa98Sdjl /*CONSTCOND*/ 672cb5caa98Sdjl while (1) { 673cb5caa98Sdjl 6749f590749Smichen (void) sleep(60); 6759f590749Smichen 676cb5caa98Sdjl (void) rw_rdlock(&getent_ctxDB_rwlock); 677cb5caa98Sdjl 678cb5caa98Sdjl for (ep = _nscd_walk_db(getent_ctxDB, &cookie); ep != NULL; 679cb5caa98Sdjl ep = _nscd_walk_db(getent_ctxDB, &cookie)) { 680cb5caa98Sdjl 681cb5caa98Sdjl ctx = (nscd_getent_ctx_t *)*(ep->data_array); 682cb5caa98Sdjl 683cb5caa98Sdjl gctx = ctx->ptr; 684cb5caa98Sdjl 685cb5caa98Sdjl /* 686cb5caa98Sdjl * if the client process, which did the setent, 687cb5caa98Sdjl * exited, add the context to the orphan list 688cb5caa98Sdjl */ 689cb5caa98Sdjl if (gctx->pid != -1 && process_exited(gctx->pid)) { 690cb5caa98Sdjl 691cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, 692cb5caa98Sdjl NSCD_LOG_LEVEL_DEBUG) 693cb5caa98Sdjl (me, "process %d exited, " 694cb5caa98Sdjl "getent context = %p, " 695e37190e5Smichen "db index = %d, cookie # = %lld, " 696cb5caa98Sdjl "sequence # = %lld\n", 697cb5caa98Sdjl gctx->pid, gctx, gctx->dbi, 698e37190e5Smichen gctx->cookie_num, gctx->seq_num); 699cb5caa98Sdjl 700cb5caa98Sdjl if (first != NULL) { 7016392794bSMichen Chang /* add to list if not in already */ 7026392794bSMichen Chang for (c = first; c != NULL; 7036392794bSMichen Chang c = c->next_to_reclaim) { 7046392794bSMichen Chang if (gctx == c) 7056392794bSMichen Chang break; 7066392794bSMichen Chang } 7076392794bSMichen Chang if (c == NULL) { 7086392794bSMichen Chang last->next_to_reclaim = gctx; 709cb5caa98Sdjl last = gctx; 7106392794bSMichen Chang } 711cb5caa98Sdjl } else { 712cb5caa98Sdjl first = gctx; 713cb5caa98Sdjl last = gctx; 714cb5caa98Sdjl } 715cb5caa98Sdjl } 716cb5caa98Sdjl } 717cb5caa98Sdjl 718cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 719cb5caa98Sdjl 720cb5caa98Sdjl 721cb5caa98Sdjl /* 72229836b19Smichen * return all the orphan getent contexts to the pool if not 72329836b19Smichen * in use 724cb5caa98Sdjl */ 725cb5caa98Sdjl for (gctx = first; gctx; ) { 7266392794bSMichen Chang int in_use, num_reclaim_check; 7276392794bSMichen Chang 7286392794bSMichen Chang c = gctx->next_to_reclaim; 7296392794bSMichen Chang gctx->next_to_reclaim = NULL; 73029836b19Smichen gctx->aborted = 1; 7316392794bSMichen Chang 73229836b19Smichen (void) mutex_lock(&gctx->getent_mutex); 7336392794bSMichen Chang num_reclaim_check = gctx->num_reclaim_check++; 7346392794bSMichen Chang if (num_reclaim_check > 1) 7356392794bSMichen Chang gctx->in_use = 0; 73629836b19Smichen in_use = gctx->in_use; 73729836b19Smichen (void) mutex_unlock(&gctx->getent_mutex); 7386392794bSMichen Chang 7396392794bSMichen Chang if (in_use == 0) { 7406392794bSMichen Chang _NSCD_LOG(NSCD_LOG_GETENT_CTX, 7416392794bSMichen Chang NSCD_LOG_LEVEL_DEBUG) 7426392794bSMichen Chang (me, "process %d exited, " 7436392794bSMichen Chang "freeing getent context = %p\n", 7446392794bSMichen Chang gctx->pid, gctx); 7456392794bSMichen Chang nssctx.ctx = (struct nss_getent_context *)gctx; 7466392794bSMichen Chang nss_endent(NULL, NULL, &nssctx); 74729836b19Smichen } 748cb5caa98Sdjl gctx = c; 749cb5caa98Sdjl } 750cb5caa98Sdjl first = last = NULL; 751cb5caa98Sdjl } 752cb5caa98Sdjl /*NOTREACHED*/ 753cb5caa98Sdjl /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ 754cb5caa98Sdjl } 755cb5caa98Sdjl 756cb5caa98Sdjl static nscd_rc_t 757cb5caa98Sdjl _nscd_init_getent_ctx_monitor() { 758cb5caa98Sdjl 759cb5caa98Sdjl int errnum; 760cb5caa98Sdjl char *me = "_nscd_init_getent_ctx_monitor"; 761cb5caa98Sdjl 762cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 763cb5caa98Sdjl (me, "initializing the getent context monitor\n"); 764cb5caa98Sdjl 765cb5caa98Sdjl /* 766cb5caa98Sdjl * the forker nscd does not process getent requests 767cb5caa98Sdjl * so no need to monitor orphan getent contexts 768cb5caa98Sdjl */ 769cb5caa98Sdjl if (_whoami == NSCD_FORKER) 770cb5caa98Sdjl return (NSCD_SUCCESS); 771cb5caa98Sdjl 772cb5caa98Sdjl /* 773cb5caa98Sdjl * start a thread to reclaim unused getent contexts 774cb5caa98Sdjl */ 775cb5caa98Sdjl if (thr_create(NULL, NULL, reclaim_getent_ctx, 776cb5caa98Sdjl NULL, THR_DETACHED, NULL) != 0) { 777cb5caa98Sdjl errnum = errno; 778cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_ERROR) 779cb5caa98Sdjl (me, "thr_create: %s\n", strerror(errnum)); 780cb5caa98Sdjl return (NSCD_THREAD_CREATE_ERROR); 781cb5caa98Sdjl } 782cb5caa98Sdjl 783cb5caa98Sdjl return (NSCD_SUCCESS); 784cb5caa98Sdjl } 785