1*cb5caa98Sdjl /* 2*cb5caa98Sdjl * CDDL HEADER START 3*cb5caa98Sdjl * 4*cb5caa98Sdjl * The contents of this file are subject to the terms of the 5*cb5caa98Sdjl * Common Development and Distribution License (the "License"). 6*cb5caa98Sdjl * You may not use this file except in compliance with the License. 7*cb5caa98Sdjl * 8*cb5caa98Sdjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*cb5caa98Sdjl * or http://www.opensolaris.org/os/licensing. 10*cb5caa98Sdjl * See the License for the specific language governing permissions 11*cb5caa98Sdjl * and limitations under the License. 12*cb5caa98Sdjl * 13*cb5caa98Sdjl * When distributing Covered Code, include this CDDL HEADER in each 14*cb5caa98Sdjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*cb5caa98Sdjl * If applicable, add the following below this CDDL HEADER, with the 16*cb5caa98Sdjl * fields enclosed by brackets "[]" replaced with your own identifying 17*cb5caa98Sdjl * information: Portions Copyright [yyyy] [name of copyright owner] 18*cb5caa98Sdjl * 19*cb5caa98Sdjl * CDDL HEADER END 20*cb5caa98Sdjl */ 21*cb5caa98Sdjl /* 22*cb5caa98Sdjl * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*cb5caa98Sdjl * Use is subject to license terms. 24*cb5caa98Sdjl */ 25*cb5caa98Sdjl 26*cb5caa98Sdjl #pragma ident "%Z%%M% %I% %E% SMI" 27*cb5caa98Sdjl 28*cb5caa98Sdjl #include <stdlib.h> 29*cb5caa98Sdjl #include <assert.h> 30*cb5caa98Sdjl #include <string.h> 31*cb5caa98Sdjl #include <errno.h> 32*cb5caa98Sdjl #include <fcntl.h> 33*cb5caa98Sdjl #include "nscd_db.h" 34*cb5caa98Sdjl #include "nscd_log.h" 35*cb5caa98Sdjl #include "nscd_switch.h" 36*cb5caa98Sdjl #include "nscd_door.h" 37*cb5caa98Sdjl 38*cb5caa98Sdjl extern int _whoami; 39*cb5caa98Sdjl static mutex_t getent_monitor_mutex = DEFAULTMUTEX; 40*cb5caa98Sdjl static int getent_monitor_started = 0; 41*cb5caa98Sdjl 42*cb5caa98Sdjl static rwlock_t getent_ctxDB_rwlock = DEFAULTRWLOCK; 43*cb5caa98Sdjl static nscd_db_t *getent_ctxDB = NULL; 44*cb5caa98Sdjl 45*cb5caa98Sdjl /* 46*cb5caa98Sdjl * internal structure representing a nscd getent context 47*cb5caa98Sdjl */ 48*cb5caa98Sdjl typedef struct nscd_getent_ctx { 49*cb5caa98Sdjl int to_delete; /* this ctx no longer valid */ 50*cb5caa98Sdjl nscd_getent_context_t *ptr; 51*cb5caa98Sdjl nscd_cookie_t cookie; 52*cb5caa98Sdjl } nscd_getent_ctx_t; 53*cb5caa98Sdjl 54*cb5caa98Sdjl /* 55*cb5caa98Sdjl * nscd_getent_context_t list for each nss database. Protected 56*cb5caa98Sdjl * by the readers/writer lock nscd_getent_ctx_lock. 57*cb5caa98Sdjl */ 58*cb5caa98Sdjl nscd_getent_ctx_base_t **nscd_getent_ctx_base; 59*cb5caa98Sdjl static rwlock_t nscd_getent_ctx_base_lock = DEFAULTRWLOCK; 60*cb5caa98Sdjl 61*cb5caa98Sdjl extern nscd_db_entry_t *_nscd_walk_db(nscd_db_t *db, void **cookie); 62*cb5caa98Sdjl 63*cb5caa98Sdjl static nscd_rc_t _nscd_init_getent_ctx_monitor(); 64*cb5caa98Sdjl 65*cb5caa98Sdjl /* 66*cb5caa98Sdjl * FUNCTION: _nscd_create_getent_ctxDB 67*cb5caa98Sdjl * 68*cb5caa98Sdjl * Create the internal getent context database to keep track of the 69*cb5caa98Sdjl * getent contexts currently being used. 70*cb5caa98Sdjl */ 71*cb5caa98Sdjl nscd_db_t * 72*cb5caa98Sdjl _nscd_create_getent_ctxDB() 73*cb5caa98Sdjl { 74*cb5caa98Sdjl 75*cb5caa98Sdjl nscd_db_t *ret; 76*cb5caa98Sdjl 77*cb5caa98Sdjl (void) rw_wrlock(&getent_ctxDB_rwlock); 78*cb5caa98Sdjl 79*cb5caa98Sdjl if (getent_ctxDB != NULL) { 80*cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 81*cb5caa98Sdjl return (getent_ctxDB); 82*cb5caa98Sdjl } 83*cb5caa98Sdjl 84*cb5caa98Sdjl ret = _nscd_alloc_db(NSCD_DB_SIZE_LARGE); 85*cb5caa98Sdjl 86*cb5caa98Sdjl if (ret != NULL) 87*cb5caa98Sdjl getent_ctxDB = ret; 88*cb5caa98Sdjl 89*cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 90*cb5caa98Sdjl 91*cb5caa98Sdjl return (ret); 92*cb5caa98Sdjl } 93*cb5caa98Sdjl 94*cb5caa98Sdjl /* 95*cb5caa98Sdjl * FUNCTION: _nscd_add_getent_ctx 96*cb5caa98Sdjl * 97*cb5caa98Sdjl * Add a getent context to the internal context database. 98*cb5caa98Sdjl */ 99*cb5caa98Sdjl static nscd_rc_t 100*cb5caa98Sdjl _nscd_add_getent_ctx( 101*cb5caa98Sdjl nscd_getent_context_t *ptr, 102*cb5caa98Sdjl nscd_cookie_t cookie) 103*cb5caa98Sdjl { 104*cb5caa98Sdjl int size; 105*cb5caa98Sdjl char buf[2 * sizeof (cookie) + 1]; 106*cb5caa98Sdjl nscd_db_entry_t *db_entry; 107*cb5caa98Sdjl nscd_getent_ctx_t *gnctx; 108*cb5caa98Sdjl 109*cb5caa98Sdjl if (ptr == NULL) 110*cb5caa98Sdjl return (NSCD_INVALID_ARGUMENT); 111*cb5caa98Sdjl 112*cb5caa98Sdjl (void) snprintf(buf, sizeof (buf), "%lld", cookie); 113*cb5caa98Sdjl 114*cb5caa98Sdjl size = sizeof (*gnctx); 115*cb5caa98Sdjl 116*cb5caa98Sdjl db_entry = _nscd_alloc_db_entry(NSCD_DATA_CTX_ADDR, 117*cb5caa98Sdjl (const char *)buf, size, 1, 1); 118*cb5caa98Sdjl if (db_entry == NULL) 119*cb5caa98Sdjl return (NSCD_NO_MEMORY); 120*cb5caa98Sdjl 121*cb5caa98Sdjl gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); 122*cb5caa98Sdjl gnctx->ptr = ptr; 123*cb5caa98Sdjl gnctx->cookie = cookie; 124*cb5caa98Sdjl 125*cb5caa98Sdjl (void) rw_wrlock(&getent_ctxDB_rwlock); 126*cb5caa98Sdjl (void) _nscd_add_db_entry(getent_ctxDB, buf, db_entry, 127*cb5caa98Sdjl NSCD_ADD_DB_ENTRY_FIRST); 128*cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 129*cb5caa98Sdjl 130*cb5caa98Sdjl return (NSCD_SUCCESS); 131*cb5caa98Sdjl } 132*cb5caa98Sdjl 133*cb5caa98Sdjl /* 134*cb5caa98Sdjl * FUNCTION: _nscd_is_getent_ctx 135*cb5caa98Sdjl * 136*cb5caa98Sdjl * Check to see if a getent context can be found in the internal 137*cb5caa98Sdjl * getent context database. 138*cb5caa98Sdjl */ 139*cb5caa98Sdjl nscd_getent_context_t * 140*cb5caa98Sdjl _nscd_is_getent_ctx( 141*cb5caa98Sdjl nscd_cookie_t cookie) 142*cb5caa98Sdjl { 143*cb5caa98Sdjl char ptrstr[1 + 2 * sizeof (cookie)]; 144*cb5caa98Sdjl const nscd_db_entry_t *db_entry; 145*cb5caa98Sdjl nscd_getent_context_t *ret = NULL; 146*cb5caa98Sdjl 147*cb5caa98Sdjl (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie); 148*cb5caa98Sdjl 149*cb5caa98Sdjl (void) rw_rdlock(&getent_ctxDB_rwlock); 150*cb5caa98Sdjl 151*cb5caa98Sdjl db_entry = _nscd_get_db_entry(getent_ctxDB, NSCD_DATA_CTX_ADDR, 152*cb5caa98Sdjl (const char *)ptrstr, NSCD_GET_FIRST_DB_ENTRY, 0); 153*cb5caa98Sdjl 154*cb5caa98Sdjl if (db_entry != NULL) { 155*cb5caa98Sdjl nscd_getent_ctx_t *gnctx; 156*cb5caa98Sdjl 157*cb5caa98Sdjl gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); 158*cb5caa98Sdjl 159*cb5caa98Sdjl /* 160*cb5caa98Sdjl * If the ctx is not to be deleted and 161*cb5caa98Sdjl * the cookie numbers match, return the ctx. 162*cb5caa98Sdjl * Otherwise return NULL. 163*cb5caa98Sdjl */ 164*cb5caa98Sdjl if (gnctx->to_delete == 0 && gnctx->cookie == cookie) 165*cb5caa98Sdjl ret = gnctx->ptr; 166*cb5caa98Sdjl } 167*cb5caa98Sdjl 168*cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 169*cb5caa98Sdjl 170*cb5caa98Sdjl return (ret); 171*cb5caa98Sdjl } 172*cb5caa98Sdjl 173*cb5caa98Sdjl /* 174*cb5caa98Sdjl * FUNCTION: _nscd_del_getent_ctx 175*cb5caa98Sdjl * 176*cb5caa98Sdjl * Delete a getent context from the internal getent context database. 177*cb5caa98Sdjl */ 178*cb5caa98Sdjl static void 179*cb5caa98Sdjl _nscd_del_getent_ctx( 180*cb5caa98Sdjl nscd_getent_context_t *ptr, 181*cb5caa98Sdjl nscd_cookie_t cookie) 182*cb5caa98Sdjl { 183*cb5caa98Sdjl char ptrstr[1 + 2 * sizeof (cookie)]; 184*cb5caa98Sdjl nscd_getent_ctx_t *gnctx; 185*cb5caa98Sdjl const nscd_db_entry_t *db_entry; 186*cb5caa98Sdjl 187*cb5caa98Sdjl if (ptr == NULL) 188*cb5caa98Sdjl return; 189*cb5caa98Sdjl 190*cb5caa98Sdjl (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie); 191*cb5caa98Sdjl 192*cb5caa98Sdjl (void) rw_rdlock(&getent_ctxDB_rwlock); 193*cb5caa98Sdjl /* 194*cb5caa98Sdjl * first find the db entry and make sure the 195*cb5caa98Sdjl * sequence number matched, then delete it from 196*cb5caa98Sdjl * the database. 197*cb5caa98Sdjl */ 198*cb5caa98Sdjl db_entry = _nscd_get_db_entry(getent_ctxDB, 199*cb5caa98Sdjl NSCD_DATA_CTX_ADDR, 200*cb5caa98Sdjl (const char *)ptrstr, 201*cb5caa98Sdjl NSCD_GET_FIRST_DB_ENTRY, 0); 202*cb5caa98Sdjl if (db_entry != NULL) { 203*cb5caa98Sdjl gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); 204*cb5caa98Sdjl if (gnctx->ptr == ptr && gnctx->cookie == cookie) { 205*cb5caa98Sdjl 206*cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 207*cb5caa98Sdjl (void) rw_wrlock(&getent_ctxDB_rwlock); 208*cb5caa98Sdjl 209*cb5caa98Sdjl (void) _nscd_delete_db_entry(getent_ctxDB, 210*cb5caa98Sdjl NSCD_DATA_CTX_ADDR, 211*cb5caa98Sdjl (const char *)ptrstr, 212*cb5caa98Sdjl NSCD_DEL_FIRST_DB_ENTRY, 0); 213*cb5caa98Sdjl } 214*cb5caa98Sdjl } 215*cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 216*cb5caa98Sdjl } 217*cb5caa98Sdjl 218*cb5caa98Sdjl static void 219*cb5caa98Sdjl _nscd_free_getent_ctx( 220*cb5caa98Sdjl nscd_getent_context_t *gnctx) 221*cb5caa98Sdjl { 222*cb5caa98Sdjl 223*cb5caa98Sdjl char *me = "_nscd_free_getent_ctx"; 224*cb5caa98Sdjl 225*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 226*cb5caa98Sdjl (me, "getent context %p\n", gnctx); 227*cb5caa98Sdjl 228*cb5caa98Sdjl _nscd_put_nsw_state(gnctx->nsw_state); 229*cb5caa98Sdjl _nscd_del_getent_ctx(gnctx, gnctx->cookie); 230*cb5caa98Sdjl free(gnctx); 231*cb5caa98Sdjl } 232*cb5caa98Sdjl 233*cb5caa98Sdjl 234*cb5caa98Sdjl static void 235*cb5caa98Sdjl _nscd_free_getent_ctx_base( 236*cb5caa98Sdjl nscd_acc_data_t *data) 237*cb5caa98Sdjl { 238*cb5caa98Sdjl nscd_getent_ctx_base_t *base = (nscd_getent_ctx_base_t *)data; 239*cb5caa98Sdjl nscd_getent_context_t *c, *tc; 240*cb5caa98Sdjl char *me = "_nscd_free_getent_ctx_base"; 241*cb5caa98Sdjl 242*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 243*cb5caa98Sdjl (me, "getent context base %p\n", base); 244*cb5caa98Sdjl 245*cb5caa98Sdjl if (base == NULL) 246*cb5caa98Sdjl return; 247*cb5caa98Sdjl 248*cb5caa98Sdjl c = base->first; 249*cb5caa98Sdjl while (c != NULL) { 250*cb5caa98Sdjl tc = c->next; 251*cb5caa98Sdjl _nscd_free_getent_ctx(c); 252*cb5caa98Sdjl c = tc; 253*cb5caa98Sdjl } 254*cb5caa98Sdjl } 255*cb5caa98Sdjl 256*cb5caa98Sdjl void 257*cb5caa98Sdjl _nscd_free_all_getent_ctx_base() 258*cb5caa98Sdjl { 259*cb5caa98Sdjl nscd_getent_ctx_base_t *base; 260*cb5caa98Sdjl int i; 261*cb5caa98Sdjl char *me = "_nscd_free_all_getent_ctx_base"; 262*cb5caa98Sdjl 263*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 264*cb5caa98Sdjl (me, "entering ..\n"); 265*cb5caa98Sdjl 266*cb5caa98Sdjl (void) rw_wrlock(&nscd_getent_ctx_base_lock); 267*cb5caa98Sdjl 268*cb5caa98Sdjl for (i = 0; i < NSCD_NUM_DB; i++) { 269*cb5caa98Sdjl 270*cb5caa98Sdjl base = nscd_getent_ctx_base[i]; 271*cb5caa98Sdjl if (base == NULL) 272*cb5caa98Sdjl continue; 273*cb5caa98Sdjl 274*cb5caa98Sdjl nscd_getent_ctx_base[i] = (nscd_getent_ctx_base_t *) 275*cb5caa98Sdjl _nscd_set((nscd_acc_data_t *)base, NULL); 276*cb5caa98Sdjl } 277*cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 278*cb5caa98Sdjl } 279*cb5caa98Sdjl 280*cb5caa98Sdjl static nscd_getent_context_t * 281*cb5caa98Sdjl _nscd_create_getent_ctx( 282*cb5caa98Sdjl nscd_nsw_params_t *params) 283*cb5caa98Sdjl { 284*cb5caa98Sdjl nscd_getent_context_t *gnctx; 285*cb5caa98Sdjl nss_db_root_t db_root; 286*cb5caa98Sdjl char *me = "_nscd_create_getent_ctx"; 287*cb5caa98Sdjl 288*cb5caa98Sdjl gnctx = calloc(1, sizeof (nscd_getent_context_t)); 289*cb5caa98Sdjl if (gnctx == NULL) 290*cb5caa98Sdjl return (NULL); 291*cb5caa98Sdjl else { 292*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 293*cb5caa98Sdjl (me, "getent context allocated %p\n", gnctx); 294*cb5caa98Sdjl } 295*cb5caa98Sdjl 296*cb5caa98Sdjl gnctx->dbi = params->dbi; 297*cb5caa98Sdjl gnctx->cookie = _nscd_get_cookie(); 298*cb5caa98Sdjl 299*cb5caa98Sdjl if (_nscd_get_nsw_state(&db_root, params) != NSCD_SUCCESS) { 300*cb5caa98Sdjl free(gnctx); 301*cb5caa98Sdjl return (NULL); 302*cb5caa98Sdjl } 303*cb5caa98Sdjl gnctx->nsw_state = (nscd_nsw_state_t *)db_root.s; 304*cb5caa98Sdjl /* this is a nsw_state used for getent processing */ 305*cb5caa98Sdjl gnctx->nsw_state->getent = 1; 306*cb5caa98Sdjl 307*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 308*cb5caa98Sdjl (me, "got nsw_state %p\n", gnctx->nsw_state); 309*cb5caa98Sdjl 310*cb5caa98Sdjl return (gnctx); 311*cb5caa98Sdjl } 312*cb5caa98Sdjl 313*cb5caa98Sdjl 314*cb5caa98Sdjl nscd_rc_t 315*cb5caa98Sdjl _nscd_get_getent_ctx( 316*cb5caa98Sdjl nss_getent_t *contextpp, 317*cb5caa98Sdjl nscd_nsw_params_t *params) 318*cb5caa98Sdjl { 319*cb5caa98Sdjl 320*cb5caa98Sdjl nscd_getent_context_t *c; 321*cb5caa98Sdjl nscd_getent_ctx_base_t *base, *tmp; 322*cb5caa98Sdjl nscd_rc_t rc; 323*cb5caa98Sdjl char *me = "_nscd_get_getent_ctx"; 324*cb5caa98Sdjl 325*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 326*cb5caa98Sdjl (me, "entering ...\n"); 327*cb5caa98Sdjl 328*cb5caa98Sdjl (void) rw_rdlock(&nscd_getent_ctx_base_lock); 329*cb5caa98Sdjl base = nscd_getent_ctx_base[params->dbi]; 330*cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 331*cb5caa98Sdjl assert(base != NULL); 332*cb5caa98Sdjl 333*cb5caa98Sdjl /* 334*cb5caa98Sdjl * If the context list is not empty, return the first one 335*cb5caa98Sdjl * on the list. Otherwise, create and return a new one if 336*cb5caa98Sdjl * limit is not reached. if reacehed, wait for the 'one is 337*cb5caa98Sdjl * available' signal. 338*cb5caa98Sdjl */ 339*cb5caa98Sdjl tmp = (nscd_getent_ctx_base_t *)_nscd_mutex_lock( 340*cb5caa98Sdjl (nscd_acc_data_t *)base); 341*cb5caa98Sdjl assert(base == tmp); 342*cb5caa98Sdjl if (base->first == NULL) { 343*cb5caa98Sdjl if (base->num_getent_ctx == base->max_getent_ctx) { 344*cb5caa98Sdjl base->num_waiter++; 345*cb5caa98Sdjl while (base->first == NULL) { 346*cb5caa98Sdjl 347*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, 348*cb5caa98Sdjl NSCD_LOG_LEVEL_DEBUG) 349*cb5caa98Sdjl (me, "waiting for signal\n"); 350*cb5caa98Sdjl 351*cb5caa98Sdjl _nscd_cond_wait((nscd_acc_data_t *)base, NULL); 352*cb5caa98Sdjl 353*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, 354*cb5caa98Sdjl NSCD_LOG_LEVEL_DEBUG) 355*cb5caa98Sdjl (me, "woke up\n"); 356*cb5caa98Sdjl } 357*cb5caa98Sdjl base->num_waiter--; 358*cb5caa98Sdjl } else { 359*cb5caa98Sdjl base->first = _nscd_create_getent_ctx(params); 360*cb5caa98Sdjl if (base->first != NULL) { 361*cb5caa98Sdjl base->first->base = base; 362*cb5caa98Sdjl base->num_getent_ctx++; 363*cb5caa98Sdjl } else { 364*cb5caa98Sdjl /* not able to create an getent ctx */ 365*cb5caa98Sdjl 366*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, 367*cb5caa98Sdjl NSCD_LOG_LEVEL_ERROR) 368*cb5caa98Sdjl (me, "create getent ctx failed\n"); 369*cb5caa98Sdjl 370*cb5caa98Sdjl _nscd_mutex_unlock((nscd_acc_data_t *)base); 371*cb5caa98Sdjl return (NSCD_CREATE_GETENT_CTX_FAILED); 372*cb5caa98Sdjl } 373*cb5caa98Sdjl 374*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 375*cb5caa98Sdjl (me, "got a new getent ctx %p\n", base->first); 376*cb5caa98Sdjl } 377*cb5caa98Sdjl } 378*cb5caa98Sdjl 379*cb5caa98Sdjl assert(base->first != NULL); 380*cb5caa98Sdjl 381*cb5caa98Sdjl c = base->first; 382*cb5caa98Sdjl base->first = c->next; 383*cb5caa98Sdjl c->next = NULL; 384*cb5caa98Sdjl c->seq_num = 1; 385*cb5caa98Sdjl 386*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 387*cb5caa98Sdjl (me, "got a getent ctx %p\n", c); 388*cb5caa98Sdjl 389*cb5caa98Sdjl _nscd_mutex_unlock((nscd_acc_data_t *)base); 390*cb5caa98Sdjl 391*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 392*cb5caa98Sdjl (me, "adding new ctx %p, cookie = %lld\n", c, c->cookie); 393*cb5caa98Sdjl 394*cb5caa98Sdjl if ((rc = _nscd_add_getent_ctx(c, c->cookie)) != NSCD_SUCCESS) { 395*cb5caa98Sdjl _nscd_put_getent_ctx(c); 396*cb5caa98Sdjl return (rc); 397*cb5caa98Sdjl } 398*cb5caa98Sdjl contextpp->ctx = (struct nss_getent_context *)c; 399*cb5caa98Sdjl 400*cb5caa98Sdjl /* start monitor and reclaim orphan getent context */ 401*cb5caa98Sdjl if (getent_monitor_started == 0) { 402*cb5caa98Sdjl (void) mutex_lock(&getent_monitor_mutex); 403*cb5caa98Sdjl if (getent_monitor_started == 0) { 404*cb5caa98Sdjl getent_monitor_started = 1; 405*cb5caa98Sdjl (void) _nscd_init_getent_ctx_monitor(); 406*cb5caa98Sdjl } 407*cb5caa98Sdjl (void) mutex_unlock(&getent_monitor_mutex); 408*cb5caa98Sdjl } 409*cb5caa98Sdjl 410*cb5caa98Sdjl return (NSCD_SUCCESS); 411*cb5caa98Sdjl } 412*cb5caa98Sdjl 413*cb5caa98Sdjl void 414*cb5caa98Sdjl _nscd_put_getent_ctx( 415*cb5caa98Sdjl nscd_getent_context_t *gnctx) 416*cb5caa98Sdjl { 417*cb5caa98Sdjl 418*cb5caa98Sdjl nscd_getent_ctx_base_t *base; 419*cb5caa98Sdjl char *me = "_nscd_put_getent_ctx"; 420*cb5caa98Sdjl 421*cb5caa98Sdjl base = gnctx->base; 422*cb5caa98Sdjl gnctx->seq_num = 0; 423*cb5caa98Sdjl 424*cb5caa98Sdjl /* if context base is gone, so should this context */ 425*cb5caa98Sdjl if ((_nscd_mutex_lock((nscd_acc_data_t *)base)) == NULL) { 426*cb5caa98Sdjl _nscd_free_getent_ctx(gnctx); 427*cb5caa98Sdjl return; 428*cb5caa98Sdjl } 429*cb5caa98Sdjl 430*cb5caa98Sdjl if (base->first != NULL) { 431*cb5caa98Sdjl gnctx->next = base->first; 432*cb5caa98Sdjl base->first = gnctx; 433*cb5caa98Sdjl } else 434*cb5caa98Sdjl base->first = gnctx; 435*cb5caa98Sdjl 436*cb5caa98Sdjl /* put back the db state */ 437*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 438*cb5caa98Sdjl (me, "putting back nsw state %p\n", gnctx->nsw_state); 439*cb5caa98Sdjl 440*cb5caa98Sdjl /* this nsw_state is no longer used for getent processing */ 441*cb5caa98Sdjl if (gnctx->nsw_state != NULL) 442*cb5caa98Sdjl gnctx->nsw_state->getent = 0; 443*cb5caa98Sdjl _nscd_put_nsw_state(gnctx->nsw_state); 444*cb5caa98Sdjl gnctx->nsw_state = NULL; 445*cb5caa98Sdjl 446*cb5caa98Sdjl _nscd_del_getent_ctx(gnctx, gnctx->cookie); 447*cb5caa98Sdjl 448*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 449*cb5caa98Sdjl (me, "ctx (%p seq# = %lld) removed from getent ctx DB\n", 450*cb5caa98Sdjl gnctx, gnctx->cookie); 451*cb5caa98Sdjl 452*cb5caa98Sdjl if (base->num_waiter > 0) { 453*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 454*cb5caa98Sdjl (me, "signaling (waiter = %d)\n", base->num_waiter); 455*cb5caa98Sdjl 456*cb5caa98Sdjl _nscd_cond_signal((nscd_acc_data_t *)base); 457*cb5caa98Sdjl } 458*cb5caa98Sdjl 459*cb5caa98Sdjl _nscd_mutex_unlock((nscd_acc_data_t *)base); 460*cb5caa98Sdjl } 461*cb5caa98Sdjl 462*cb5caa98Sdjl nscd_rc_t 463*cb5caa98Sdjl _nscd_init_getent_ctx_base( 464*cb5caa98Sdjl int dbi, 465*cb5caa98Sdjl int lock) 466*cb5caa98Sdjl { 467*cb5caa98Sdjl nscd_getent_ctx_base_t *base = NULL; 468*cb5caa98Sdjl char *me = "_nscd_init_getent_ctx_base"; 469*cb5caa98Sdjl 470*cb5caa98Sdjl if (lock) 471*cb5caa98Sdjl (void) rw_rdlock(&nscd_getent_ctx_base_lock); 472*cb5caa98Sdjl 473*cb5caa98Sdjl base = (nscd_getent_ctx_base_t *)_nscd_alloc( 474*cb5caa98Sdjl NSCD_DATA_GETENT_CTX_BASE, 475*cb5caa98Sdjl sizeof (nscd_getent_ctx_base_t), 476*cb5caa98Sdjl _nscd_free_getent_ctx_base, 477*cb5caa98Sdjl NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND); 478*cb5caa98Sdjl 479*cb5caa98Sdjl if (base == NULL) { 480*cb5caa98Sdjl if (lock) 481*cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 482*cb5caa98Sdjl return (NSCD_NO_MEMORY); 483*cb5caa98Sdjl } 484*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 485*cb5caa98Sdjl (me, "base %p allocated\n", base); 486*cb5caa98Sdjl 487*cb5caa98Sdjl /* 488*cb5caa98Sdjl * initialize and activate the new getent_ctx base 489*cb5caa98Sdjl */ 490*cb5caa98Sdjl base->dbi = dbi; 491*cb5caa98Sdjl base->max_getent_ctx = NSCD_SW_CFG(dbi).max_getent_ctx_per_db; 492*cb5caa98Sdjl nscd_getent_ctx_base[dbi] = 493*cb5caa98Sdjl (nscd_getent_ctx_base_t *)_nscd_set( 494*cb5caa98Sdjl (nscd_acc_data_t *)nscd_getent_ctx_base[dbi], 495*cb5caa98Sdjl (nscd_acc_data_t *)base); 496*cb5caa98Sdjl 497*cb5caa98Sdjl if (lock) 498*cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 499*cb5caa98Sdjl 500*cb5caa98Sdjl return (NSCD_SUCCESS); 501*cb5caa98Sdjl } 502*cb5caa98Sdjl 503*cb5caa98Sdjl nscd_rc_t 504*cb5caa98Sdjl _nscd_init_all_getent_ctx_base() 505*cb5caa98Sdjl { 506*cb5caa98Sdjl int i; 507*cb5caa98Sdjl nscd_rc_t rc; 508*cb5caa98Sdjl char *me = "_nscd_init_all_getent_ctx_base"; 509*cb5caa98Sdjl 510*cb5caa98Sdjl (void) rw_wrlock(&nscd_getent_ctx_base_lock); 511*cb5caa98Sdjl 512*cb5caa98Sdjl for (i = 0; i < NSCD_NUM_DB; i++) { 513*cb5caa98Sdjl 514*cb5caa98Sdjl rc = _nscd_init_getent_ctx_base(i, 0); 515*cb5caa98Sdjl 516*cb5caa98Sdjl if (rc != NSCD_SUCCESS) { 517*cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 518*cb5caa98Sdjl return (rc); 519*cb5caa98Sdjl } 520*cb5caa98Sdjl } 521*cb5caa98Sdjl 522*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 523*cb5caa98Sdjl (me, "all getent context base initialized\n"); 524*cb5caa98Sdjl 525*cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 526*cb5caa98Sdjl 527*cb5caa98Sdjl return (NSCD_SUCCESS); 528*cb5caa98Sdjl } 529*cb5caa98Sdjl nscd_rc_t 530*cb5caa98Sdjl _nscd_alloc_getent_ctx_base() 531*cb5caa98Sdjl { 532*cb5caa98Sdjl 533*cb5caa98Sdjl (void) rw_wrlock(&nscd_getent_ctx_base_lock); 534*cb5caa98Sdjl 535*cb5caa98Sdjl nscd_getent_ctx_base = calloc(NSCD_NUM_DB, 536*cb5caa98Sdjl sizeof (nscd_getent_ctx_base_t *)); 537*cb5caa98Sdjl if (nscd_getent_ctx_base == NULL) { 538*cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 539*cb5caa98Sdjl return (NSCD_NO_MEMORY); 540*cb5caa98Sdjl } 541*cb5caa98Sdjl 542*cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock); 543*cb5caa98Sdjl 544*cb5caa98Sdjl return (NSCD_SUCCESS); 545*cb5caa98Sdjl } 546*cb5caa98Sdjl 547*cb5caa98Sdjl static int 548*cb5caa98Sdjl process_exited(pid_t pid) 549*cb5caa98Sdjl { 550*cb5caa98Sdjl char pname[PATH_MAX]; 551*cb5caa98Sdjl int fd; 552*cb5caa98Sdjl 553*cb5caa98Sdjl (void) snprintf(pname, sizeof (pname), "/proc/%d/psinfo", pid); 554*cb5caa98Sdjl if ((fd = open(pname, O_RDONLY)) == -1) 555*cb5caa98Sdjl return (1); 556*cb5caa98Sdjl else { 557*cb5caa98Sdjl (void) close(fd); 558*cb5caa98Sdjl return (0); 559*cb5caa98Sdjl } 560*cb5caa98Sdjl } 561*cb5caa98Sdjl 562*cb5caa98Sdjl /* 563*cb5caa98Sdjl * FUNCTION: reclaim_getent_ctx 564*cb5caa98Sdjl */ 565*cb5caa98Sdjl /*ARGSUSED*/ 566*cb5caa98Sdjl static void * 567*cb5caa98Sdjl reclaim_getent_ctx(void *arg) 568*cb5caa98Sdjl { 569*cb5caa98Sdjl void *cookie = NULL; 570*cb5caa98Sdjl nscd_db_entry_t *ep; 571*cb5caa98Sdjl nscd_getent_ctx_t *ctx; 572*cb5caa98Sdjl nscd_getent_context_t *gctx, *c; 573*cb5caa98Sdjl nscd_getent_context_t *first = NULL, *last = NULL; 574*cb5caa98Sdjl char *me = "reclaim_getent_ctx"; 575*cb5caa98Sdjl 576*cb5caa98Sdjl /*CONSTCOND*/ 577*cb5caa98Sdjl while (1) { 578*cb5caa98Sdjl 579*cb5caa98Sdjl (void) rw_rdlock(&getent_ctxDB_rwlock); 580*cb5caa98Sdjl 581*cb5caa98Sdjl for (ep = _nscd_walk_db(getent_ctxDB, &cookie); ep != NULL; 582*cb5caa98Sdjl ep = _nscd_walk_db(getent_ctxDB, &cookie)) { 583*cb5caa98Sdjl 584*cb5caa98Sdjl ctx = (nscd_getent_ctx_t *)*(ep->data_array); 585*cb5caa98Sdjl 586*cb5caa98Sdjl gctx = ctx->ptr; 587*cb5caa98Sdjl 588*cb5caa98Sdjl /* 589*cb5caa98Sdjl * if the client process, which did the setent, 590*cb5caa98Sdjl * exited, add the context to the orphan list 591*cb5caa98Sdjl */ 592*cb5caa98Sdjl if (gctx->pid != -1 && process_exited(gctx->pid)) { 593*cb5caa98Sdjl 594*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, 595*cb5caa98Sdjl NSCD_LOG_LEVEL_DEBUG) 596*cb5caa98Sdjl (me, "process %d exited, " 597*cb5caa98Sdjl "getent context = %p, " 598*cb5caa98Sdjl "db index = %d, cookie = %lld, " 599*cb5caa98Sdjl "sequence # = %lld\n", 600*cb5caa98Sdjl gctx->pid, gctx, gctx->dbi, 601*cb5caa98Sdjl gctx->cookie, gctx->seq_num); 602*cb5caa98Sdjl 603*cb5caa98Sdjl if (first != NULL) { 604*cb5caa98Sdjl last->next = gctx; 605*cb5caa98Sdjl last = gctx; 606*cb5caa98Sdjl } else { 607*cb5caa98Sdjl first = gctx; 608*cb5caa98Sdjl last = gctx; 609*cb5caa98Sdjl } 610*cb5caa98Sdjl } 611*cb5caa98Sdjl } 612*cb5caa98Sdjl 613*cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock); 614*cb5caa98Sdjl 615*cb5caa98Sdjl 616*cb5caa98Sdjl /* 617*cb5caa98Sdjl * return all the orphan getent contexts to the pool 618*cb5caa98Sdjl */ 619*cb5caa98Sdjl for (gctx = first; gctx; ) { 620*cb5caa98Sdjl c = gctx->next; 621*cb5caa98Sdjl gctx->next = NULL; 622*cb5caa98Sdjl _nscd_put_getent_ctx(gctx); 623*cb5caa98Sdjl gctx = c; 624*cb5caa98Sdjl } 625*cb5caa98Sdjl first = last = NULL; 626*cb5caa98Sdjl 627*cb5caa98Sdjl (void) sleep(60); 628*cb5caa98Sdjl } 629*cb5caa98Sdjl /*NOTREACHED*/ 630*cb5caa98Sdjl /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ 631*cb5caa98Sdjl } 632*cb5caa98Sdjl 633*cb5caa98Sdjl static nscd_rc_t 634*cb5caa98Sdjl _nscd_init_getent_ctx_monitor() { 635*cb5caa98Sdjl 636*cb5caa98Sdjl int errnum; 637*cb5caa98Sdjl char *me = "_nscd_init_getent_ctx_monitor"; 638*cb5caa98Sdjl 639*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) 640*cb5caa98Sdjl (me, "initializing the getent context monitor\n"); 641*cb5caa98Sdjl 642*cb5caa98Sdjl /* 643*cb5caa98Sdjl * the forker nscd does not process getent requests 644*cb5caa98Sdjl * so no need to monitor orphan getent contexts 645*cb5caa98Sdjl */ 646*cb5caa98Sdjl if (_whoami == NSCD_FORKER) 647*cb5caa98Sdjl return (NSCD_SUCCESS); 648*cb5caa98Sdjl 649*cb5caa98Sdjl /* 650*cb5caa98Sdjl * start a thread to reclaim unused getent contexts 651*cb5caa98Sdjl */ 652*cb5caa98Sdjl if (thr_create(NULL, NULL, reclaim_getent_ctx, 653*cb5caa98Sdjl NULL, THR_DETACHED, NULL) != 0) { 654*cb5caa98Sdjl errnum = errno; 655*cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_ERROR) 656*cb5caa98Sdjl (me, "thr_create: %s\n", strerror(errnum)); 657*cb5caa98Sdjl return (NSCD_THREAD_CREATE_ERROR); 658*cb5caa98Sdjl } 659*cb5caa98Sdjl 660*cb5caa98Sdjl return (NSCD_SUCCESS); 661*cb5caa98Sdjl } 662