blob: 2fed9a5c82b24b4b512d1eb8ee1d5a71111b0160 [file] [log] [blame]
djlcb5caa92006-09-29 06:00:17 -07001/*
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/*
Michen Changcfed26c2009-10-24 07:00:32 -070022 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
djlcb5caa92006-09-29 06:00:17 -070023 * Use is subject to license terms.
24 */
25
Richard Lowe9e293962011-05-16 06:20:47 +010026#include <sys/ccompile.h>
27
djlcb5caa92006-09-29 06:00:17 -070028#include <stdlib.h>
29#include <assert.h>
30#include <string.h>
31#include <errno.h>
32#include <fcntl.h>
Richard Lowe9e293962011-05-16 06:20:47 +010033
djlcb5caa92006-09-29 06:00:17 -070034#include "nscd_db.h"
35#include "nscd_log.h"
36#include "nscd_switch.h"
37#include "nscd_door.h"
38
39extern int _whoami;
40static mutex_t getent_monitor_mutex = DEFAULTMUTEX;
41static int getent_monitor_started = 0;
42
43static rwlock_t getent_ctxDB_rwlock = DEFAULTRWLOCK;
44static nscd_db_t *getent_ctxDB = NULL;
45
46/*
47 * internal structure representing a nscd getent context
48 */
49typedef struct nscd_getent_ctx {
50 int to_delete; /* this ctx no longer valid */
51 nscd_getent_context_t *ptr;
michene37190e2006-11-12 19:14:12 -080052 nscd_cookie_num_t cookie_num;
djlcb5caa92006-09-29 06:00:17 -070053} nscd_getent_ctx_t;
54
55/*
56 * nscd_getent_context_t list for each nss database. Protected
57 * by the readers/writer lock nscd_getent_ctx_lock.
58 */
59nscd_getent_ctx_base_t **nscd_getent_ctx_base;
60static rwlock_t nscd_getent_ctx_base_lock = DEFAULTRWLOCK;
61
62extern nscd_db_entry_t *_nscd_walk_db(nscd_db_t *db, void **cookie);
63
64static nscd_rc_t _nscd_init_getent_ctx_monitor();
65
66/*
67 * FUNCTION: _nscd_create_getent_ctxDB
68 *
69 * Create the internal getent context database to keep track of the
70 * getent contexts currently being used.
71 */
72nscd_db_t *
73_nscd_create_getent_ctxDB()
74{
75
76 nscd_db_t *ret;
77
78 (void) rw_wrlock(&getent_ctxDB_rwlock);
79
80 if (getent_ctxDB != NULL) {
81 (void) rw_unlock(&getent_ctxDB_rwlock);
82 return (getent_ctxDB);
83 }
84
85 ret = _nscd_alloc_db(NSCD_DB_SIZE_LARGE);
86
87 if (ret != NULL)
88 getent_ctxDB = ret;
89
90 (void) rw_unlock(&getent_ctxDB_rwlock);
91
92 return (ret);
93}
94
95/*
96 * FUNCTION: _nscd_add_getent_ctx
97 *
98 * Add a getent context to the internal context database.
99 */
100static nscd_rc_t
101_nscd_add_getent_ctx(
102 nscd_getent_context_t *ptr,
michene37190e2006-11-12 19:14:12 -0800103 nscd_cookie_num_t cookie_num)
djlcb5caa92006-09-29 06:00:17 -0700104{
105 int size;
michen29836b12008-08-04 08:31:06 -0700106 char buf[32];
djlcb5caa92006-09-29 06:00:17 -0700107 nscd_db_entry_t *db_entry;
108 nscd_getent_ctx_t *gnctx;
109
110 if (ptr == NULL)
111 return (NSCD_INVALID_ARGUMENT);
112
michene37190e2006-11-12 19:14:12 -0800113 (void) snprintf(buf, sizeof (buf), "%lld", cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700114
115 size = sizeof (*gnctx);
116
117 db_entry = _nscd_alloc_db_entry(NSCD_DATA_CTX_ADDR,
michen29836b12008-08-04 08:31:06 -0700118 (const char *)buf, size, 1, 1);
djlcb5caa92006-09-29 06:00:17 -0700119 if (db_entry == NULL)
120 return (NSCD_NO_MEMORY);
121
122 gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array);
123 gnctx->ptr = ptr;
michene37190e2006-11-12 19:14:12 -0800124 gnctx->cookie_num = cookie_num;
djlcb5caa92006-09-29 06:00:17 -0700125
126 (void) rw_wrlock(&getent_ctxDB_rwlock);
127 (void) _nscd_add_db_entry(getent_ctxDB, buf, db_entry,
michen29836b12008-08-04 08:31:06 -0700128 NSCD_ADD_DB_ENTRY_FIRST);
djlcb5caa92006-09-29 06:00:17 -0700129 (void) rw_unlock(&getent_ctxDB_rwlock);
130
131 return (NSCD_SUCCESS);
132}
133
134/*
135 * FUNCTION: _nscd_is_getent_ctx
136 *
137 * Check to see if a getent context can be found in the internal
138 * getent context database.
139 */
140nscd_getent_context_t *
141_nscd_is_getent_ctx(
michene37190e2006-11-12 19:14:12 -0800142 nscd_cookie_num_t cookie_num)
djlcb5caa92006-09-29 06:00:17 -0700143{
michen29836b12008-08-04 08:31:06 -0700144 char ptrstr[32];
djlcb5caa92006-09-29 06:00:17 -0700145 const nscd_db_entry_t *db_entry;
146 nscd_getent_context_t *ret = NULL;
Michen Chang63927942008-09-29 17:06:39 -0700147 char *me = "_nscd_is_getent_ctx";
djlcb5caa92006-09-29 06:00:17 -0700148
michene37190e2006-11-12 19:14:12 -0800149 (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700150
151 (void) rw_rdlock(&getent_ctxDB_rwlock);
152
153 db_entry = _nscd_get_db_entry(getent_ctxDB, NSCD_DATA_CTX_ADDR,
michen29836b12008-08-04 08:31:06 -0700154 (const char *)ptrstr, NSCD_GET_FIRST_DB_ENTRY, 0);
djlcb5caa92006-09-29 06:00:17 -0700155
156 if (db_entry != NULL) {
157 nscd_getent_ctx_t *gnctx;
158
159 gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array);
Michen Chang63927942008-09-29 17:06:39 -0700160 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
161 (me, "getent context %p, cookie# %lld, to_delete %d\n",
162 gnctx->ptr, gnctx->cookie_num, gnctx->to_delete);
djlcb5caa92006-09-29 06:00:17 -0700163
164 /*
Michen Chang63927942008-09-29 17:06:39 -0700165 * If the ctx is not to be deleted and the cookie numbers
Michen Changcfed26c2009-10-24 07:00:32 -0700166 * match, return the ctx if not aborted and not in use.
djlcb5caa92006-09-29 06:00:17 -0700167 * Otherwise return NULL.
168 */
michen29836b12008-08-04 08:31:06 -0700169 if (gnctx->to_delete == 0 && gnctx->cookie_num == cookie_num) {
djlcb5caa92006-09-29 06:00:17 -0700170 ret = gnctx->ptr;
michen29836b12008-08-04 08:31:06 -0700171 (void) mutex_lock(&gnctx->ptr->getent_mutex);
172 if (ret->aborted == 1 || ret->in_use == 1)
173 ret = NULL;
174 else
175 ret->in_use = 1;
176 (void) mutex_unlock(&gnctx->ptr->getent_mutex);
177 }
djlcb5caa92006-09-29 06:00:17 -0700178 }
179
180 (void) rw_unlock(&getent_ctxDB_rwlock);
181
182 return (ret);
183}
184
Michen Chang63927942008-09-29 17:06:39 -0700185int
186_nscd_is_getent_ctx_in_use(
187 nscd_getent_context_t *ctx)
188{
189 int in_use;
190 char *me = "_nscd_getent_ctx_in_use";
191
192 (void) mutex_lock(&ctx->getent_mutex);
193
194 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
195 (me, "in_use = %d, ctx->thr_id = %d, thread id = %d\n",
196 ctx->in_use, ctx->thr_id, thr_self());
197
198 in_use = ctx->in_use;
199 if (in_use == 1 && ctx->thr_id == thr_self())
200 in_use = 0;
201 (void) mutex_unlock(&ctx->getent_mutex);
202 return (in_use);
203}
204
djlcb5caa92006-09-29 06:00:17 -0700205/*
michen29836b12008-08-04 08:31:06 -0700206 * FUNCTION: _nscd_free_ctx_if_aborted
207 *
208 * Check to see if the getent session associated with a getent context had
209 * been aborted. If so, return the getent context back to the pool.
210 */
211void
212_nscd_free_ctx_if_aborted(
213 nscd_getent_context_t *ctx)
214{
215 int aborted;
216 char *me = "_nscd_free_ctx_if_aborted";
217
michen29836b12008-08-04 08:31:06 -0700218 (void) mutex_lock(&ctx->getent_mutex);
Michen Chang63927942008-09-29 17:06:39 -0700219
220 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
221 (me, "in_use = %d, aborted = %d\n", ctx->in_use, ctx->aborted);
222
223 if (ctx->in_use != 1) {
224 (void) mutex_unlock(&ctx->getent_mutex);
225 return;
226 }
michen29836b12008-08-04 08:31:06 -0700227 aborted = ctx->aborted;
Michen Chang63927942008-09-29 17:06:39 -0700228 ctx->in_use = 0;
michen29836b12008-08-04 08:31:06 -0700229 (void) mutex_unlock(&ctx->getent_mutex);
230
231 if (aborted == 1) {
232 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
233 (me, "getent session aborted, return the getent context\n");
234 _nscd_put_getent_ctx(ctx);
235 }
michen29836b12008-08-04 08:31:06 -0700236}
237
238/*
djlcb5caa92006-09-29 06:00:17 -0700239 * FUNCTION: _nscd_del_getent_ctx
240 *
241 * Delete a getent context from the internal getent context database.
242 */
243static void
244_nscd_del_getent_ctx(
245 nscd_getent_context_t *ptr,
michene37190e2006-11-12 19:14:12 -0800246 nscd_cookie_num_t cookie_num)
djlcb5caa92006-09-29 06:00:17 -0700247{
michen29836b12008-08-04 08:31:06 -0700248 char ptrstr[32];
djlcb5caa92006-09-29 06:00:17 -0700249 nscd_getent_ctx_t *gnctx;
250 const nscd_db_entry_t *db_entry;
251
252 if (ptr == NULL)
253 return;
254
michene37190e2006-11-12 19:14:12 -0800255 (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700256
257 (void) rw_rdlock(&getent_ctxDB_rwlock);
258 /*
259 * first find the db entry and make sure the
260 * sequence number matched, then delete it from
261 * the database.
262 */
263 db_entry = _nscd_get_db_entry(getent_ctxDB,
michen29836b12008-08-04 08:31:06 -0700264 NSCD_DATA_CTX_ADDR,
265 (const char *)ptrstr,
266 NSCD_GET_FIRST_DB_ENTRY, 0);
djlcb5caa92006-09-29 06:00:17 -0700267 if (db_entry != NULL) {
268 gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array);
michene37190e2006-11-12 19:14:12 -0800269 if (gnctx->ptr == ptr && gnctx->cookie_num == cookie_num) {
djlcb5caa92006-09-29 06:00:17 -0700270
271 (void) rw_unlock(&getent_ctxDB_rwlock);
272 (void) rw_wrlock(&getent_ctxDB_rwlock);
273
274 (void) _nscd_delete_db_entry(getent_ctxDB,
michen29836b12008-08-04 08:31:06 -0700275 NSCD_DATA_CTX_ADDR,
276 (const char *)ptrstr,
277 NSCD_DEL_FIRST_DB_ENTRY, 0);
djlcb5caa92006-09-29 06:00:17 -0700278 }
279 }
280 (void) rw_unlock(&getent_ctxDB_rwlock);
281}
282
283static void
284_nscd_free_getent_ctx(
285 nscd_getent_context_t *gnctx)
286{
287
288 char *me = "_nscd_free_getent_ctx";
289
290 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
291 (me, "getent context %p\n", gnctx);
292
293 _nscd_put_nsw_state(gnctx->nsw_state);
Michen Changcfed26c2009-10-24 07:00:32 -0700294
295 if (gnctx->base != NULL) {
296 /* remove reference to the getent context base */
297 _nscd_release((nscd_acc_data_t *)gnctx->base);
298 gnctx->base = NULL;
299 }
300
michene37190e2006-11-12 19:14:12 -0800301 _nscd_del_getent_ctx(gnctx, gnctx->cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700302 free(gnctx);
303}
304
305
306static void
307_nscd_free_getent_ctx_base(
308 nscd_acc_data_t *data)
309{
310 nscd_getent_ctx_base_t *base = (nscd_getent_ctx_base_t *)data;
311 nscd_getent_context_t *c, *tc;
312 char *me = "_nscd_free_getent_ctx_base";
313
314 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
315 (me, "getent context base %p\n", base);
316
317 if (base == NULL)
318 return;
319
320 c = base->first;
321 while (c != NULL) {
322 tc = c->next;
323 _nscd_free_getent_ctx(c);
324 c = tc;
325 }
326}
327
328void
329_nscd_free_all_getent_ctx_base()
330{
331 nscd_getent_ctx_base_t *base;
332 int i;
333 char *me = "_nscd_free_all_getent_ctx_base";
334
335 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
336 (me, "entering ..\n");
337
338 (void) rw_wrlock(&nscd_getent_ctx_base_lock);
339
340 for (i = 0; i < NSCD_NUM_DB; i++) {
341
342 base = nscd_getent_ctx_base[i];
343 if (base == NULL)
344 continue;
345
346 nscd_getent_ctx_base[i] = (nscd_getent_ctx_base_t *)
michen29836b12008-08-04 08:31:06 -0700347 _nscd_set((nscd_acc_data_t *)base, NULL);
djlcb5caa92006-09-29 06:00:17 -0700348 }
349 (void) rw_unlock(&nscd_getent_ctx_base_lock);
350}
351
352static nscd_getent_context_t *
353_nscd_create_getent_ctx(
354 nscd_nsw_params_t *params)
355{
356 nscd_getent_context_t *gnctx;
357 nss_db_root_t db_root;
358 char *me = "_nscd_create_getent_ctx";
359
360 gnctx = calloc(1, sizeof (nscd_getent_context_t));
361 if (gnctx == NULL)
362 return (NULL);
363 else {
364 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
365 (me, "getent context allocated %p\n", gnctx);
366 }
367
368 gnctx->dbi = params->dbi;
michene37190e2006-11-12 19:14:12 -0800369 gnctx->cookie_num = _nscd_get_cookie_num();
michen9f590742006-10-12 19:12:54 -0700370 gnctx->pid = -1;
michen29836b12008-08-04 08:31:06 -0700371 (void) mutex_init(&gnctx->getent_mutex, USYNC_THREAD, NULL);
djlcb5caa92006-09-29 06:00:17 -0700372
373 if (_nscd_get_nsw_state(&db_root, params) != NSCD_SUCCESS) {
374 free(gnctx);
375 return (NULL);
376 }
377 gnctx->nsw_state = (nscd_nsw_state_t *)db_root.s;
378 /* this is a nsw_state used for getent processing */
379 gnctx->nsw_state->getent = 1;
380
381 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
382 (me, "got nsw_state %p\n", gnctx->nsw_state);
383
384 return (gnctx);
385}
386
387
388nscd_rc_t
389_nscd_get_getent_ctx(
390 nss_getent_t *contextpp,
391 nscd_nsw_params_t *params)
392{
393
394 nscd_getent_context_t *c;
395 nscd_getent_ctx_base_t *base, *tmp;
396 nscd_rc_t rc;
397 char *me = "_nscd_get_getent_ctx";
398
399 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
400 (me, "entering ...\n");
401
402 (void) rw_rdlock(&nscd_getent_ctx_base_lock);
403 base = nscd_getent_ctx_base[params->dbi];
404 (void) rw_unlock(&nscd_getent_ctx_base_lock);
405 assert(base != NULL);
406
407 /*
408 * If the context list is not empty, return the first one
409 * on the list. Otherwise, create and return a new one if
Julian Pullen978eb142009-11-26 14:36:04 +0000410 * limit is not reached. If limit is reached return an error
411 * so that the client can perform the enumeration.
djlcb5caa92006-09-29 06:00:17 -0700412 */
413 tmp = (nscd_getent_ctx_base_t *)_nscd_mutex_lock(
michen29836b12008-08-04 08:31:06 -0700414 (nscd_acc_data_t *)base);
djlcb5caa92006-09-29 06:00:17 -0700415 assert(base == tmp);
416 if (base->first == NULL) {
Julian Pullen978eb142009-11-26 14:36:04 +0000417 if (base->num_getent_ctx >= base->max_getent_ctx) {
418 /* run out of contexts */
djlcb5caa92006-09-29 06:00:17 -0700419
Julian Pullen978eb142009-11-26 14:36:04 +0000420 _NSCD_LOG(NSCD_LOG_GETENT_CTX,
421 NSCD_LOG_LEVEL_DEBUG)
422 (me, "run out of getent ctxs\n");
djlcb5caa92006-09-29 06:00:17 -0700423
Julian Pullen978eb142009-11-26 14:36:04 +0000424 _nscd_mutex_unlock((nscd_acc_data_t *)base);
425 return (NSCD_CREATE_GETENT_CTX_FAILED);
djlcb5caa92006-09-29 06:00:17 -0700426 } else {
427 base->first = _nscd_create_getent_ctx(params);
Michen Changcfed26c2009-10-24 07:00:32 -0700428 if (base->first != NULL)
djlcb5caa92006-09-29 06:00:17 -0700429 base->num_getent_ctx++;
Michen Changcfed26c2009-10-24 07:00:32 -0700430 else {
431 /* not able to create a getent ctx */
djlcb5caa92006-09-29 06:00:17 -0700432
433 _NSCD_LOG(NSCD_LOG_GETENT_CTX,
michen29836b12008-08-04 08:31:06 -0700434 NSCD_LOG_LEVEL_ERROR)
djlcb5caa92006-09-29 06:00:17 -0700435 (me, "create getent ctx failed\n");
436
437 _nscd_mutex_unlock((nscd_acc_data_t *)base);
438 return (NSCD_CREATE_GETENT_CTX_FAILED);
439 }
440
441 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
442 (me, "got a new getent ctx %p\n", base->first);
443 }
444 }
445
446 assert(base->first != NULL);
447
448 c = base->first;
449 base->first = c->next;
450 c->next = NULL;
451 c->seq_num = 1;
Michen Chang63927942008-09-29 17:06:39 -0700452 c->cookie_num = _nscd_get_cookie_num();
michen29836b12008-08-04 08:31:06 -0700453 c->in_use = 1;
Michen Chang63927942008-09-29 17:06:39 -0700454 c->thr_id = thr_self();
djlcb5caa92006-09-29 06:00:17 -0700455
456 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
457 (me, "got a getent ctx %p\n", c);
458
Michen Changcfed26c2009-10-24 07:00:32 -0700459 /*
460 * reference count the getent context base bfore handing out
461 * the getent context
462 */
463 c->base = (nscd_getent_ctx_base_t *)
464 _nscd_get((nscd_acc_data_t *)base);
465
djlcb5caa92006-09-29 06:00:17 -0700466 _nscd_mutex_unlock((nscd_acc_data_t *)base);
467
468 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
michene37190e2006-11-12 19:14:12 -0800469 (me, "adding new ctx %p, cookie # = %lld\n", c, c->cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700470
michene37190e2006-11-12 19:14:12 -0800471 if ((rc = _nscd_add_getent_ctx(c, c->cookie_num)) != NSCD_SUCCESS) {
djlcb5caa92006-09-29 06:00:17 -0700472 _nscd_put_getent_ctx(c);
473 return (rc);
474 }
475 contextpp->ctx = (struct nss_getent_context *)c;
476
477 /* start monitor and reclaim orphan getent context */
478 if (getent_monitor_started == 0) {
479 (void) mutex_lock(&getent_monitor_mutex);
480 if (getent_monitor_started == 0) {
481 getent_monitor_started = 1;
482 (void) _nscd_init_getent_ctx_monitor();
483 }
484 (void) mutex_unlock(&getent_monitor_mutex);
485 }
486
487 return (NSCD_SUCCESS);
488}
489
490void
491_nscd_put_getent_ctx(
492 nscd_getent_context_t *gnctx)
493{
494
495 nscd_getent_ctx_base_t *base;
496 char *me = "_nscd_put_getent_ctx";
497
498 base = gnctx->base;
djlcb5caa92006-09-29 06:00:17 -0700499
Michen Changcfed26c2009-10-24 07:00:32 -0700500 /* if context base is gone or no longer current, free this context */
djlcb5caa92006-09-29 06:00:17 -0700501 if ((_nscd_mutex_lock((nscd_acc_data_t *)base)) == NULL) {
502 _nscd_free_getent_ctx(gnctx);
503 return;
504 }
505
506 if (base->first != NULL) {
507 gnctx->next = base->first;
508 base->first = gnctx;
509 } else
510 base->first = gnctx;
511
512 /* put back the db state */
513 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
514 (me, "putting back nsw state %p\n", gnctx->nsw_state);
515
516 /* this nsw_state is no longer used for getent processing */
Michen Chang63927942008-09-29 17:06:39 -0700517 if (gnctx->nsw_state != NULL) {
djlcb5caa92006-09-29 06:00:17 -0700518 gnctx->nsw_state->getent = 0;
Michen Chang63927942008-09-29 17:06:39 -0700519 _nscd_put_nsw_state(gnctx->nsw_state);
520 gnctx->nsw_state = NULL;
521 }
djlcb5caa92006-09-29 06:00:17 -0700522
michen29836b12008-08-04 08:31:06 -0700523 gnctx->aborted = 0;
524 gnctx->in_use = 0;
Michen Chang63927942008-09-29 17:06:39 -0700525 gnctx->thr_id = (thread_t)-1;
michene37190e2006-11-12 19:14:12 -0800526 _nscd_del_getent_ctx(gnctx, gnctx->cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700527
528 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
michene37190e2006-11-12 19:14:12 -0800529 (me, "ctx (%p, cookie # = %lld) removed from getent ctx DB\n",
michen29836b12008-08-04 08:31:06 -0700530 gnctx, gnctx->cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700531
Michen Chang63927942008-09-29 17:06:39 -0700532 gnctx->seq_num = 0;
533 gnctx->cookie_num = 0;
534 gnctx->pid = -1;
535 gnctx->thr_id = (thread_t)-1;
536 gnctx->n_src = 0;
537 gnctx->be = NULL;
538
Michen Changcfed26c2009-10-24 07:00:32 -0700539 /* remove reference to the getent context base */
540 _nscd_release((nscd_acc_data_t *)base);
541 gnctx->base = NULL;
542
djlcb5caa92006-09-29 06:00:17 -0700543 _nscd_mutex_unlock((nscd_acc_data_t *)base);
544}
545
546nscd_rc_t
547_nscd_init_getent_ctx_base(
548 int dbi,
549 int lock)
550{
551 nscd_getent_ctx_base_t *base = NULL;
552 char *me = "_nscd_init_getent_ctx_base";
553
554 if (lock)
555 (void) rw_rdlock(&nscd_getent_ctx_base_lock);
556
557 base = (nscd_getent_ctx_base_t *)_nscd_alloc(
michen29836b12008-08-04 08:31:06 -0700558 NSCD_DATA_GETENT_CTX_BASE,
559 sizeof (nscd_getent_ctx_base_t),
560 _nscd_free_getent_ctx_base,
561 NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND);
djlcb5caa92006-09-29 06:00:17 -0700562
563 if (base == NULL) {
564 if (lock)
565 (void) rw_unlock(&nscd_getent_ctx_base_lock);
566 return (NSCD_NO_MEMORY);
567 }
568 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
569 (me, "base %p allocated\n", base);
570
571 /*
572 * initialize and activate the new getent_ctx base
573 */
574 base->dbi = dbi;
575 base->max_getent_ctx = NSCD_SW_CFG(dbi).max_getent_ctx_per_db;
576 nscd_getent_ctx_base[dbi] =
michen29836b12008-08-04 08:31:06 -0700577 (nscd_getent_ctx_base_t *)_nscd_set(
578 (nscd_acc_data_t *)nscd_getent_ctx_base[dbi],
579 (nscd_acc_data_t *)base);
djlcb5caa92006-09-29 06:00:17 -0700580
581 if (lock)
582 (void) rw_unlock(&nscd_getent_ctx_base_lock);
583
584 return (NSCD_SUCCESS);
585}
586
587nscd_rc_t
588_nscd_init_all_getent_ctx_base()
589{
590 int i;
591 nscd_rc_t rc;
592 char *me = "_nscd_init_all_getent_ctx_base";
593
594 (void) rw_wrlock(&nscd_getent_ctx_base_lock);
595
596 for (i = 0; i < NSCD_NUM_DB; i++) {
597
598 rc = _nscd_init_getent_ctx_base(i, 0);
599
600 if (rc != NSCD_SUCCESS) {
601 (void) rw_unlock(&nscd_getent_ctx_base_lock);
602 return (rc);
603 }
604 }
605
606 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
607 (me, "all getent context base initialized\n");
608
609 (void) rw_unlock(&nscd_getent_ctx_base_lock);
610
611 return (NSCD_SUCCESS);
612}
613nscd_rc_t
614_nscd_alloc_getent_ctx_base()
615{
616
617 (void) rw_wrlock(&nscd_getent_ctx_base_lock);
618
619 nscd_getent_ctx_base = calloc(NSCD_NUM_DB,
michen29836b12008-08-04 08:31:06 -0700620 sizeof (nscd_getent_ctx_base_t *));
djlcb5caa92006-09-29 06:00:17 -0700621 if (nscd_getent_ctx_base == NULL) {
622 (void) rw_unlock(&nscd_getent_ctx_base_lock);
623 return (NSCD_NO_MEMORY);
624 }
625
626 (void) rw_unlock(&nscd_getent_ctx_base_lock);
627
628 return (NSCD_SUCCESS);
629}
630
631static int
632process_exited(pid_t pid)
633{
634 char pname[PATH_MAX];
635 int fd;
636
637 (void) snprintf(pname, sizeof (pname), "/proc/%d/psinfo", pid);
638 if ((fd = open(pname, O_RDONLY)) == -1)
639 return (1);
640 else {
641 (void) close(fd);
642 return (0);
643 }
644}
645
646/*
647 * FUNCTION: reclaim_getent_ctx
648 */
649/*ARGSUSED*/
Richard Lowe9e293962011-05-16 06:20:47 +0100650static void * __NORETURN
djlcb5caa92006-09-29 06:00:17 -0700651reclaim_getent_ctx(void *arg)
652{
653 void *cookie = NULL;
654 nscd_db_entry_t *ep;
655 nscd_getent_ctx_t *ctx;
656 nscd_getent_context_t *gctx, *c;
657 nscd_getent_context_t *first = NULL, *last = NULL;
Michen Chang63927942008-09-29 17:06:39 -0700658 nss_getent_t nssctx = { 0 };
djlcb5caa92006-09-29 06:00:17 -0700659 char *me = "reclaim_getent_ctx";
660
661 /*CONSTCOND*/
662 while (1) {
663
michen9f590742006-10-12 19:12:54 -0700664 (void) sleep(60);
665
djlcb5caa92006-09-29 06:00:17 -0700666 (void) rw_rdlock(&getent_ctxDB_rwlock);
667
668 for (ep = _nscd_walk_db(getent_ctxDB, &cookie); ep != NULL;
michen29836b12008-08-04 08:31:06 -0700669 ep = _nscd_walk_db(getent_ctxDB, &cookie)) {
djlcb5caa92006-09-29 06:00:17 -0700670
671 ctx = (nscd_getent_ctx_t *)*(ep->data_array);
672
673 gctx = ctx->ptr;
674
675 /*
676 * if the client process, which did the setent,
677 * exited, add the context to the orphan list
678 */
679 if (gctx->pid != -1 && process_exited(gctx->pid)) {
680
681 _NSCD_LOG(NSCD_LOG_GETENT_CTX,
michen29836b12008-08-04 08:31:06 -0700682 NSCD_LOG_LEVEL_DEBUG)
djlcb5caa92006-09-29 06:00:17 -0700683 (me, "process %d exited, "
michen29836b12008-08-04 08:31:06 -0700684 "getent context = %p, "
685 "db index = %d, cookie # = %lld, "
686 "sequence # = %lld\n",
687 gctx->pid, gctx, gctx->dbi,
688 gctx->cookie_num, gctx->seq_num);
djlcb5caa92006-09-29 06:00:17 -0700689
690 if (first != NULL) {
Michen Chang63927942008-09-29 17:06:39 -0700691 /* add to list if not in already */
692 for (c = first; c != NULL;
693 c = c->next_to_reclaim) {
694 if (gctx == c)
695 break;
696 }
697 if (c == NULL) {
698 last->next_to_reclaim = gctx;
699 last = gctx;
700 }
djlcb5caa92006-09-29 06:00:17 -0700701 } else {
702 first = gctx;
703 last = gctx;
704 }
705 }
706 }
707
708 (void) rw_unlock(&getent_ctxDB_rwlock);
709
710
711 /*
michen29836b12008-08-04 08:31:06 -0700712 * return all the orphan getent contexts to the pool if not
713 * in use
djlcb5caa92006-09-29 06:00:17 -0700714 */
715 for (gctx = first; gctx; ) {
Michen Chang63927942008-09-29 17:06:39 -0700716 int in_use, num_reclaim_check;
717
718 c = gctx->next_to_reclaim;
719 gctx->next_to_reclaim = NULL;
michen29836b12008-08-04 08:31:06 -0700720 gctx->aborted = 1;
Michen Chang63927942008-09-29 17:06:39 -0700721
michen29836b12008-08-04 08:31:06 -0700722 (void) mutex_lock(&gctx->getent_mutex);
Michen Chang63927942008-09-29 17:06:39 -0700723 num_reclaim_check = gctx->num_reclaim_check++;
724 if (num_reclaim_check > 1)
725 gctx->in_use = 0;
michen29836b12008-08-04 08:31:06 -0700726 in_use = gctx->in_use;
727 (void) mutex_unlock(&gctx->getent_mutex);
Michen Chang63927942008-09-29 17:06:39 -0700728
729 if (in_use == 0) {
730 _NSCD_LOG(NSCD_LOG_GETENT_CTX,
731 NSCD_LOG_LEVEL_DEBUG)
732 (me, "process %d exited, "
733 "freeing getent context = %p\n",
734 gctx->pid, gctx);
735 nssctx.ctx = (struct nss_getent_context *)gctx;
736 nss_endent(NULL, NULL, &nssctx);
michen29836b12008-08-04 08:31:06 -0700737 }
djlcb5caa92006-09-29 06:00:17 -0700738 gctx = c;
739 }
740 first = last = NULL;
djlcb5caa92006-09-29 06:00:17 -0700741 }
742 /*NOTREACHED*/
743 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
744}
745
746static nscd_rc_t
747_nscd_init_getent_ctx_monitor() {
748
749 int errnum;
750 char *me = "_nscd_init_getent_ctx_monitor";
751
752 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
753 (me, "initializing the getent context monitor\n");
754
755 /*
756 * the forker nscd does not process getent requests
757 * so no need to monitor orphan getent contexts
758 */
759 if (_whoami == NSCD_FORKER)
760 return (NSCD_SUCCESS);
761
762 /*
763 * start a thread to reclaim unused getent contexts
764 */
765 if (thr_create(NULL, NULL, reclaim_getent_ctx,
766 NULL, THR_DETACHED, NULL) != 0) {
767 errnum = errno;
768 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_ERROR)
769 (me, "thr_create: %s\n", strerror(errnum));
770 return (NSCD_THREAD_CREATE_ERROR);
771 }
772
773 return (NSCD_SUCCESS);
774}