blob: f4e6b89fbc911deadbc230a1611374b4f0d071dc [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.
John Levonab618542018-10-08 15:34:11 +010024 *
25 * Copyright 2018 Joyent, Inc.
djlcb5caa92006-09-29 06:00:17 -070026 */
27
Richard Lowe9e293962011-05-16 06:20:47 +010028#include <sys/ccompile.h>
29
djlcb5caa92006-09-29 06:00:17 -070030#include <stdlib.h>
31#include <assert.h>
32#include <string.h>
33#include <errno.h>
34#include <fcntl.h>
Richard Lowe9e293962011-05-16 06:20:47 +010035
djlcb5caa92006-09-29 06:00:17 -070036#include "nscd_db.h"
37#include "nscd_log.h"
38#include "nscd_switch.h"
39#include "nscd_door.h"
40
41extern int _whoami;
42static mutex_t getent_monitor_mutex = DEFAULTMUTEX;
43static int getent_monitor_started = 0;
44
45static rwlock_t getent_ctxDB_rwlock = DEFAULTRWLOCK;
46static nscd_db_t *getent_ctxDB = NULL;
47
48/*
49 * internal structure representing a nscd getent context
50 */
51typedef struct nscd_getent_ctx {
52 int to_delete; /* this ctx no longer valid */
53 nscd_getent_context_t *ptr;
michene37190e2006-11-12 19:14:12 -080054 nscd_cookie_num_t cookie_num;
djlcb5caa92006-09-29 06:00:17 -070055} nscd_getent_ctx_t;
56
57/*
58 * nscd_getent_context_t list for each nss database. Protected
59 * by the readers/writer lock nscd_getent_ctx_lock.
60 */
61nscd_getent_ctx_base_t **nscd_getent_ctx_base;
62static rwlock_t nscd_getent_ctx_base_lock = DEFAULTRWLOCK;
63
64extern nscd_db_entry_t *_nscd_walk_db(nscd_db_t *db, void **cookie);
65
66static nscd_rc_t _nscd_init_getent_ctx_monitor();
67
68/*
69 * FUNCTION: _nscd_create_getent_ctxDB
70 *
71 * Create the internal getent context database to keep track of the
72 * getent contexts currently being used.
73 */
74nscd_db_t *
75_nscd_create_getent_ctxDB()
76{
77
78 nscd_db_t *ret;
79
80 (void) rw_wrlock(&getent_ctxDB_rwlock);
81
82 if (getent_ctxDB != NULL) {
83 (void) rw_unlock(&getent_ctxDB_rwlock);
84 return (getent_ctxDB);
85 }
86
87 ret = _nscd_alloc_db(NSCD_DB_SIZE_LARGE);
88
89 if (ret != NULL)
90 getent_ctxDB = ret;
91
92 (void) rw_unlock(&getent_ctxDB_rwlock);
93
94 return (ret);
95}
96
97/*
98 * FUNCTION: _nscd_add_getent_ctx
99 *
100 * Add a getent context to the internal context database.
101 */
102static nscd_rc_t
103_nscd_add_getent_ctx(
104 nscd_getent_context_t *ptr,
michene37190e2006-11-12 19:14:12 -0800105 nscd_cookie_num_t cookie_num)
djlcb5caa92006-09-29 06:00:17 -0700106{
107 int size;
michen29836b12008-08-04 08:31:06 -0700108 char buf[32];
djlcb5caa92006-09-29 06:00:17 -0700109 nscd_db_entry_t *db_entry;
110 nscd_getent_ctx_t *gnctx;
111
112 if (ptr == NULL)
113 return (NSCD_INVALID_ARGUMENT);
114
michene37190e2006-11-12 19:14:12 -0800115 (void) snprintf(buf, sizeof (buf), "%lld", cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700116
117 size = sizeof (*gnctx);
118
119 db_entry = _nscd_alloc_db_entry(NSCD_DATA_CTX_ADDR,
michen29836b12008-08-04 08:31:06 -0700120 (const char *)buf, size, 1, 1);
djlcb5caa92006-09-29 06:00:17 -0700121 if (db_entry == NULL)
122 return (NSCD_NO_MEMORY);
123
124 gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array);
125 gnctx->ptr = ptr;
michene37190e2006-11-12 19:14:12 -0800126 gnctx->cookie_num = cookie_num;
djlcb5caa92006-09-29 06:00:17 -0700127
128 (void) rw_wrlock(&getent_ctxDB_rwlock);
129 (void) _nscd_add_db_entry(getent_ctxDB, buf, db_entry,
michen29836b12008-08-04 08:31:06 -0700130 NSCD_ADD_DB_ENTRY_FIRST);
djlcb5caa92006-09-29 06:00:17 -0700131 (void) rw_unlock(&getent_ctxDB_rwlock);
132
133 return (NSCD_SUCCESS);
134}
135
136/*
137 * FUNCTION: _nscd_is_getent_ctx
138 *
139 * Check to see if a getent context can be found in the internal
140 * getent context database.
141 */
142nscd_getent_context_t *
143_nscd_is_getent_ctx(
michene37190e2006-11-12 19:14:12 -0800144 nscd_cookie_num_t cookie_num)
djlcb5caa92006-09-29 06:00:17 -0700145{
michen29836b12008-08-04 08:31:06 -0700146 char ptrstr[32];
djlcb5caa92006-09-29 06:00:17 -0700147 const nscd_db_entry_t *db_entry;
148 nscd_getent_context_t *ret = NULL;
Michen Chang63927942008-09-29 17:06:39 -0700149 char *me = "_nscd_is_getent_ctx";
djlcb5caa92006-09-29 06:00:17 -0700150
michene37190e2006-11-12 19:14:12 -0800151 (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700152
153 (void) rw_rdlock(&getent_ctxDB_rwlock);
154
155 db_entry = _nscd_get_db_entry(getent_ctxDB, NSCD_DATA_CTX_ADDR,
michen29836b12008-08-04 08:31:06 -0700156 (const char *)ptrstr, NSCD_GET_FIRST_DB_ENTRY, 0);
djlcb5caa92006-09-29 06:00:17 -0700157
158 if (db_entry != NULL) {
159 nscd_getent_ctx_t *gnctx;
160
161 gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array);
Michen Chang63927942008-09-29 17:06:39 -0700162 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
163 (me, "getent context %p, cookie# %lld, to_delete %d\n",
164 gnctx->ptr, gnctx->cookie_num, gnctx->to_delete);
djlcb5caa92006-09-29 06:00:17 -0700165
166 /*
Michen Chang63927942008-09-29 17:06:39 -0700167 * If the ctx is not to be deleted and the cookie numbers
Michen Changcfed26c2009-10-24 07:00:32 -0700168 * match, return the ctx if not aborted and not in use.
djlcb5caa92006-09-29 06:00:17 -0700169 * Otherwise return NULL.
170 */
michen29836b12008-08-04 08:31:06 -0700171 if (gnctx->to_delete == 0 && gnctx->cookie_num == cookie_num) {
djlcb5caa92006-09-29 06:00:17 -0700172 ret = gnctx->ptr;
michen29836b12008-08-04 08:31:06 -0700173 (void) mutex_lock(&gnctx->ptr->getent_mutex);
174 if (ret->aborted == 1 || ret->in_use == 1)
175 ret = NULL;
176 else
177 ret->in_use = 1;
178 (void) mutex_unlock(&gnctx->ptr->getent_mutex);
179 }
djlcb5caa92006-09-29 06:00:17 -0700180 }
181
182 (void) rw_unlock(&getent_ctxDB_rwlock);
183
184 return (ret);
185}
186
Michen Chang63927942008-09-29 17:06:39 -0700187int
188_nscd_is_getent_ctx_in_use(
189 nscd_getent_context_t *ctx)
190{
191 int in_use;
192 char *me = "_nscd_getent_ctx_in_use";
193
194 (void) mutex_lock(&ctx->getent_mutex);
195
196 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
197 (me, "in_use = %d, ctx->thr_id = %d, thread id = %d\n",
198 ctx->in_use, ctx->thr_id, thr_self());
199
200 in_use = ctx->in_use;
201 if (in_use == 1 && ctx->thr_id == thr_self())
202 in_use = 0;
203 (void) mutex_unlock(&ctx->getent_mutex);
204 return (in_use);
205}
206
djlcb5caa92006-09-29 06:00:17 -0700207/*
michen29836b12008-08-04 08:31:06 -0700208 * FUNCTION: _nscd_free_ctx_if_aborted
209 *
210 * Check to see if the getent session associated with a getent context had
211 * been aborted. If so, return the getent context back to the pool.
212 */
213void
214_nscd_free_ctx_if_aborted(
215 nscd_getent_context_t *ctx)
216{
217 int aborted;
218 char *me = "_nscd_free_ctx_if_aborted";
219
michen29836b12008-08-04 08:31:06 -0700220 (void) mutex_lock(&ctx->getent_mutex);
Michen Chang63927942008-09-29 17:06:39 -0700221
222 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
223 (me, "in_use = %d, aborted = %d\n", ctx->in_use, ctx->aborted);
224
225 if (ctx->in_use != 1) {
226 (void) mutex_unlock(&ctx->getent_mutex);
227 return;
228 }
michen29836b12008-08-04 08:31:06 -0700229 aborted = ctx->aborted;
Michen Chang63927942008-09-29 17:06:39 -0700230 ctx->in_use = 0;
michen29836b12008-08-04 08:31:06 -0700231 (void) mutex_unlock(&ctx->getent_mutex);
232
233 if (aborted == 1) {
234 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
235 (me, "getent session aborted, return the getent context\n");
236 _nscd_put_getent_ctx(ctx);
237 }
michen29836b12008-08-04 08:31:06 -0700238}
239
240/*
djlcb5caa92006-09-29 06:00:17 -0700241 * FUNCTION: _nscd_del_getent_ctx
242 *
243 * Delete a getent context from the internal getent context database.
244 */
245static void
246_nscd_del_getent_ctx(
247 nscd_getent_context_t *ptr,
michene37190e2006-11-12 19:14:12 -0800248 nscd_cookie_num_t cookie_num)
djlcb5caa92006-09-29 06:00:17 -0700249{
michen29836b12008-08-04 08:31:06 -0700250 char ptrstr[32];
djlcb5caa92006-09-29 06:00:17 -0700251 nscd_getent_ctx_t *gnctx;
252 const nscd_db_entry_t *db_entry;
253
254 if (ptr == NULL)
255 return;
256
michene37190e2006-11-12 19:14:12 -0800257 (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700258
259 (void) rw_rdlock(&getent_ctxDB_rwlock);
260 /*
261 * first find the db entry and make sure the
262 * sequence number matched, then delete it from
263 * the database.
264 */
265 db_entry = _nscd_get_db_entry(getent_ctxDB,
michen29836b12008-08-04 08:31:06 -0700266 NSCD_DATA_CTX_ADDR,
267 (const char *)ptrstr,
268 NSCD_GET_FIRST_DB_ENTRY, 0);
djlcb5caa92006-09-29 06:00:17 -0700269 if (db_entry != NULL) {
270 gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array);
michene37190e2006-11-12 19:14:12 -0800271 if (gnctx->ptr == ptr && gnctx->cookie_num == cookie_num) {
djlcb5caa92006-09-29 06:00:17 -0700272
273 (void) rw_unlock(&getent_ctxDB_rwlock);
274 (void) rw_wrlock(&getent_ctxDB_rwlock);
275
276 (void) _nscd_delete_db_entry(getent_ctxDB,
michen29836b12008-08-04 08:31:06 -0700277 NSCD_DATA_CTX_ADDR,
278 (const char *)ptrstr,
279 NSCD_DEL_FIRST_DB_ENTRY, 0);
djlcb5caa92006-09-29 06:00:17 -0700280 }
281 }
282 (void) rw_unlock(&getent_ctxDB_rwlock);
283}
284
285static void
286_nscd_free_getent_ctx(
287 nscd_getent_context_t *gnctx)
288{
289
290 char *me = "_nscd_free_getent_ctx";
291
292 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
293 (me, "getent context %p\n", gnctx);
294
295 _nscd_put_nsw_state(gnctx->nsw_state);
Michen Changcfed26c2009-10-24 07:00:32 -0700296
297 if (gnctx->base != NULL) {
298 /* remove reference to the getent context base */
299 _nscd_release((nscd_acc_data_t *)gnctx->base);
300 gnctx->base = NULL;
301 }
302
michene37190e2006-11-12 19:14:12 -0800303 _nscd_del_getent_ctx(gnctx, gnctx->cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700304 free(gnctx);
305}
306
307
308static void
309_nscd_free_getent_ctx_base(
310 nscd_acc_data_t *data)
311{
312 nscd_getent_ctx_base_t *base = (nscd_getent_ctx_base_t *)data;
313 nscd_getent_context_t *c, *tc;
314 char *me = "_nscd_free_getent_ctx_base";
315
316 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
317 (me, "getent context base %p\n", base);
318
319 if (base == NULL)
320 return;
321
322 c = base->first;
323 while (c != NULL) {
324 tc = c->next;
325 _nscd_free_getent_ctx(c);
326 c = tc;
327 }
328}
329
330void
331_nscd_free_all_getent_ctx_base()
332{
333 nscd_getent_ctx_base_t *base;
334 int i;
335 char *me = "_nscd_free_all_getent_ctx_base";
336
337 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
338 (me, "entering ..\n");
339
340 (void) rw_wrlock(&nscd_getent_ctx_base_lock);
341
342 for (i = 0; i < NSCD_NUM_DB; i++) {
343
344 base = nscd_getent_ctx_base[i];
345 if (base == NULL)
346 continue;
347
348 nscd_getent_ctx_base[i] = (nscd_getent_ctx_base_t *)
michen29836b12008-08-04 08:31:06 -0700349 _nscd_set((nscd_acc_data_t *)base, NULL);
djlcb5caa92006-09-29 06:00:17 -0700350 }
351 (void) rw_unlock(&nscd_getent_ctx_base_lock);
352}
353
354static nscd_getent_context_t *
355_nscd_create_getent_ctx(
356 nscd_nsw_params_t *params)
357{
358 nscd_getent_context_t *gnctx;
359 nss_db_root_t db_root;
360 char *me = "_nscd_create_getent_ctx";
361
362 gnctx = calloc(1, sizeof (nscd_getent_context_t));
363 if (gnctx == NULL)
364 return (NULL);
365 else {
366 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
367 (me, "getent context allocated %p\n", gnctx);
368 }
369
370 gnctx->dbi = params->dbi;
michene37190e2006-11-12 19:14:12 -0800371 gnctx->cookie_num = _nscd_get_cookie_num();
michen9f590742006-10-12 19:12:54 -0700372 gnctx->pid = -1;
michen29836b12008-08-04 08:31:06 -0700373 (void) mutex_init(&gnctx->getent_mutex, USYNC_THREAD, NULL);
djlcb5caa92006-09-29 06:00:17 -0700374
375 if (_nscd_get_nsw_state(&db_root, params) != NSCD_SUCCESS) {
376 free(gnctx);
377 return (NULL);
378 }
379 gnctx->nsw_state = (nscd_nsw_state_t *)db_root.s;
380 /* this is a nsw_state used for getent processing */
381 gnctx->nsw_state->getent = 1;
382
383 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
384 (me, "got nsw_state %p\n", gnctx->nsw_state);
385
386 return (gnctx);
387}
388
389
390nscd_rc_t
391_nscd_get_getent_ctx(
392 nss_getent_t *contextpp,
393 nscd_nsw_params_t *params)
394{
395
396 nscd_getent_context_t *c;
397 nscd_getent_ctx_base_t *base, *tmp;
398 nscd_rc_t rc;
399 char *me = "_nscd_get_getent_ctx";
400
401 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
402 (me, "entering ...\n");
403
404 (void) rw_rdlock(&nscd_getent_ctx_base_lock);
405 base = nscd_getent_ctx_base[params->dbi];
406 (void) rw_unlock(&nscd_getent_ctx_base_lock);
407 assert(base != NULL);
408
409 /*
410 * If the context list is not empty, return the first one
411 * on the list. Otherwise, create and return a new one if
Julian Pullen978eb142009-11-26 14:36:04 +0000412 * limit is not reached. If limit is reached return an error
413 * so that the client can perform the enumeration.
djlcb5caa92006-09-29 06:00:17 -0700414 */
415 tmp = (nscd_getent_ctx_base_t *)_nscd_mutex_lock(
michen29836b12008-08-04 08:31:06 -0700416 (nscd_acc_data_t *)base);
djlcb5caa92006-09-29 06:00:17 -0700417 assert(base == tmp);
418 if (base->first == NULL) {
Julian Pullen978eb142009-11-26 14:36:04 +0000419 if (base->num_getent_ctx >= base->max_getent_ctx) {
420 /* run out of contexts */
djlcb5caa92006-09-29 06:00:17 -0700421
Julian Pullen978eb142009-11-26 14:36:04 +0000422 _NSCD_LOG(NSCD_LOG_GETENT_CTX,
423 NSCD_LOG_LEVEL_DEBUG)
424 (me, "run out of getent ctxs\n");
djlcb5caa92006-09-29 06:00:17 -0700425
Julian Pullen978eb142009-11-26 14:36:04 +0000426 _nscd_mutex_unlock((nscd_acc_data_t *)base);
427 return (NSCD_CREATE_GETENT_CTX_FAILED);
djlcb5caa92006-09-29 06:00:17 -0700428 } else {
429 base->first = _nscd_create_getent_ctx(params);
Michen Changcfed26c2009-10-24 07:00:32 -0700430 if (base->first != NULL)
djlcb5caa92006-09-29 06:00:17 -0700431 base->num_getent_ctx++;
Michen Changcfed26c2009-10-24 07:00:32 -0700432 else {
433 /* not able to create a getent ctx */
djlcb5caa92006-09-29 06:00:17 -0700434
435 _NSCD_LOG(NSCD_LOG_GETENT_CTX,
michen29836b12008-08-04 08:31:06 -0700436 NSCD_LOG_LEVEL_ERROR)
djlcb5caa92006-09-29 06:00:17 -0700437 (me, "create getent ctx failed\n");
438
439 _nscd_mutex_unlock((nscd_acc_data_t *)base);
440 return (NSCD_CREATE_GETENT_CTX_FAILED);
441 }
442
443 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
444 (me, "got a new getent ctx %p\n", base->first);
445 }
446 }
447
448 assert(base->first != NULL);
449
450 c = base->first;
451 base->first = c->next;
452 c->next = NULL;
453 c->seq_num = 1;
Michen Chang63927942008-09-29 17:06:39 -0700454 c->cookie_num = _nscd_get_cookie_num();
michen29836b12008-08-04 08:31:06 -0700455 c->in_use = 1;
Michen Chang63927942008-09-29 17:06:39 -0700456 c->thr_id = thr_self();
djlcb5caa92006-09-29 06:00:17 -0700457
458 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
459 (me, "got a getent ctx %p\n", c);
460
Michen Changcfed26c2009-10-24 07:00:32 -0700461 /*
462 * reference count the getent context base bfore handing out
463 * the getent context
464 */
465 c->base = (nscd_getent_ctx_base_t *)
466 _nscd_get((nscd_acc_data_t *)base);
467
djlcb5caa92006-09-29 06:00:17 -0700468 _nscd_mutex_unlock((nscd_acc_data_t *)base);
469
470 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
michene37190e2006-11-12 19:14:12 -0800471 (me, "adding new ctx %p, cookie # = %lld\n", c, c->cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700472
michene37190e2006-11-12 19:14:12 -0800473 if ((rc = _nscd_add_getent_ctx(c, c->cookie_num)) != NSCD_SUCCESS) {
djlcb5caa92006-09-29 06:00:17 -0700474 _nscd_put_getent_ctx(c);
475 return (rc);
476 }
477 contextpp->ctx = (struct nss_getent_context *)c;
478
479 /* start monitor and reclaim orphan getent context */
480 if (getent_monitor_started == 0) {
481 (void) mutex_lock(&getent_monitor_mutex);
482 if (getent_monitor_started == 0) {
483 getent_monitor_started = 1;
484 (void) _nscd_init_getent_ctx_monitor();
485 }
486 (void) mutex_unlock(&getent_monitor_mutex);
487 }
488
489 return (NSCD_SUCCESS);
490}
491
492void
493_nscd_put_getent_ctx(
494 nscd_getent_context_t *gnctx)
495{
496
497 nscd_getent_ctx_base_t *base;
498 char *me = "_nscd_put_getent_ctx";
499
500 base = gnctx->base;
djlcb5caa92006-09-29 06:00:17 -0700501
Michen Changcfed26c2009-10-24 07:00:32 -0700502 /* if context base is gone or no longer current, free this context */
djlcb5caa92006-09-29 06:00:17 -0700503 if ((_nscd_mutex_lock((nscd_acc_data_t *)base)) == NULL) {
504 _nscd_free_getent_ctx(gnctx);
505 return;
506 }
507
508 if (base->first != NULL) {
509 gnctx->next = base->first;
510 base->first = gnctx;
511 } else
512 base->first = gnctx;
513
514 /* put back the db state */
515 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
516 (me, "putting back nsw state %p\n", gnctx->nsw_state);
517
518 /* this nsw_state is no longer used for getent processing */
Michen Chang63927942008-09-29 17:06:39 -0700519 if (gnctx->nsw_state != NULL) {
djlcb5caa92006-09-29 06:00:17 -0700520 gnctx->nsw_state->getent = 0;
Michen Chang63927942008-09-29 17:06:39 -0700521 _nscd_put_nsw_state(gnctx->nsw_state);
522 gnctx->nsw_state = NULL;
523 }
djlcb5caa92006-09-29 06:00:17 -0700524
michen29836b12008-08-04 08:31:06 -0700525 gnctx->aborted = 0;
526 gnctx->in_use = 0;
Michen Chang63927942008-09-29 17:06:39 -0700527 gnctx->thr_id = (thread_t)-1;
michene37190e2006-11-12 19:14:12 -0800528 _nscd_del_getent_ctx(gnctx, gnctx->cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700529
530 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
michene37190e2006-11-12 19:14:12 -0800531 (me, "ctx (%p, cookie # = %lld) removed from getent ctx DB\n",
michen29836b12008-08-04 08:31:06 -0700532 gnctx, gnctx->cookie_num);
djlcb5caa92006-09-29 06:00:17 -0700533
Michen Chang63927942008-09-29 17:06:39 -0700534 gnctx->seq_num = 0;
535 gnctx->cookie_num = 0;
536 gnctx->pid = -1;
537 gnctx->thr_id = (thread_t)-1;
538 gnctx->n_src = 0;
539 gnctx->be = NULL;
540
Michen Changcfed26c2009-10-24 07:00:32 -0700541 /* remove reference to the getent context base */
542 _nscd_release((nscd_acc_data_t *)base);
543 gnctx->base = NULL;
544
djlcb5caa92006-09-29 06:00:17 -0700545 _nscd_mutex_unlock((nscd_acc_data_t *)base);
546}
547
548nscd_rc_t
549_nscd_init_getent_ctx_base(
550 int dbi,
551 int lock)
552{
553 nscd_getent_ctx_base_t *base = NULL;
554 char *me = "_nscd_init_getent_ctx_base";
555
556 if (lock)
557 (void) rw_rdlock(&nscd_getent_ctx_base_lock);
558
559 base = (nscd_getent_ctx_base_t *)_nscd_alloc(
michen29836b12008-08-04 08:31:06 -0700560 NSCD_DATA_GETENT_CTX_BASE,
561 sizeof (nscd_getent_ctx_base_t),
562 _nscd_free_getent_ctx_base,
563 NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND);
djlcb5caa92006-09-29 06:00:17 -0700564
565 if (base == NULL) {
566 if (lock)
567 (void) rw_unlock(&nscd_getent_ctx_base_lock);
568 return (NSCD_NO_MEMORY);
569 }
570 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
571 (me, "base %p allocated\n", base);
572
573 /*
574 * initialize and activate the new getent_ctx base
575 */
576 base->dbi = dbi;
577 base->max_getent_ctx = NSCD_SW_CFG(dbi).max_getent_ctx_per_db;
578 nscd_getent_ctx_base[dbi] =
michen29836b12008-08-04 08:31:06 -0700579 (nscd_getent_ctx_base_t *)_nscd_set(
580 (nscd_acc_data_t *)nscd_getent_ctx_base[dbi],
581 (nscd_acc_data_t *)base);
djlcb5caa92006-09-29 06:00:17 -0700582
583 if (lock)
584 (void) rw_unlock(&nscd_getent_ctx_base_lock);
585
586 return (NSCD_SUCCESS);
587}
588
589nscd_rc_t
590_nscd_init_all_getent_ctx_base()
591{
592 int i;
593 nscd_rc_t rc;
594 char *me = "_nscd_init_all_getent_ctx_base";
595
596 (void) rw_wrlock(&nscd_getent_ctx_base_lock);
597
598 for (i = 0; i < NSCD_NUM_DB; i++) {
599
600 rc = _nscd_init_getent_ctx_base(i, 0);
601
602 if (rc != NSCD_SUCCESS) {
603 (void) rw_unlock(&nscd_getent_ctx_base_lock);
604 return (rc);
605 }
606 }
607
608 _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
609 (me, "all getent context base initialized\n");
610
611 (void) rw_unlock(&nscd_getent_ctx_base_lock);
612
613 return (NSCD_SUCCESS);
614}
615nscd_rc_t
616_nscd_alloc_getent_ctx_base()
617{
618
619 (void) rw_wrlock(&nscd_getent_ctx_base_lock);
620
621 nscd_getent_ctx_base = calloc(NSCD_NUM_DB,
michen29836b12008-08-04 08:31:06 -0700622 sizeof (nscd_getent_ctx_base_t *));
djlcb5caa92006-09-29 06:00:17 -0700623 if (nscd_getent_ctx_base == NULL) {
624 (void) rw_unlock(&nscd_getent_ctx_base_lock);
625 return (NSCD_NO_MEMORY);
626 }
627
628 (void) rw_unlock(&nscd_getent_ctx_base_lock);
629
630 return (NSCD_SUCCESS);
631}
632
633static int
634process_exited(pid_t pid)
635{
636 char pname[PATH_MAX];
637 int fd;
638
639 (void) snprintf(pname, sizeof (pname), "/proc/%d/psinfo", pid);
640 if ((fd = open(pname, O_RDONLY)) == -1)
641 return (1);
642 else {
643 (void) close(fd);
644 return (0);
645 }
646}
647
648/*
649 * FUNCTION: reclaim_getent_ctx
650 */
651/*ARGSUSED*/
Richard Lowe9e293962011-05-16 06:20:47 +0100652static void * __NORETURN
djlcb5caa92006-09-29 06:00:17 -0700653reclaim_getent_ctx(void *arg)
654{
655 void *cookie = NULL;
656 nscd_db_entry_t *ep;
657 nscd_getent_ctx_t *ctx;
658 nscd_getent_context_t *gctx, *c;
659 nscd_getent_context_t *first = NULL, *last = NULL;
Michen Chang63927942008-09-29 17:06:39 -0700660 nss_getent_t nssctx = { 0 };
djlcb5caa92006-09-29 06:00:17 -0700661 char *me = "reclaim_getent_ctx";
662
John Levonab618542018-10-08 15:34:11 +0100663 (void) thr_setname(thr_self(), me);
664
djlcb5caa92006-09-29 06:00:17 -0700665 /*CONSTCOND*/
666 while (1) {
667
michen9f590742006-10-12 19:12:54 -0700668 (void) sleep(60);
669
djlcb5caa92006-09-29 06:00:17 -0700670 (void) rw_rdlock(&getent_ctxDB_rwlock);
671
672 for (ep = _nscd_walk_db(getent_ctxDB, &cookie); ep != NULL;
michen29836b12008-08-04 08:31:06 -0700673 ep = _nscd_walk_db(getent_ctxDB, &cookie)) {
djlcb5caa92006-09-29 06:00:17 -0700674
675 ctx = (nscd_getent_ctx_t *)*(ep->data_array);
676
677 gctx = ctx->ptr;
678
679 /*
680 * if the client process, which did the setent,
681 * exited, add the context to the orphan list
682 */
683 if (gctx->pid != -1 && process_exited(gctx->pid)) {
684
685 _NSCD_LOG(NSCD_LOG_GETENT_CTX,
michen29836b12008-08-04 08:31:06 -0700686 NSCD_LOG_LEVEL_DEBUG)
djlcb5caa92006-09-29 06:00:17 -0700687 (me, "process %d exited, "
michen29836b12008-08-04 08:31:06 -0700688 "getent context = %p, "
689 "db index = %d, cookie # = %lld, "
690 "sequence # = %lld\n",
691 gctx->pid, gctx, gctx->dbi,
692 gctx->cookie_num, gctx->seq_num);
djlcb5caa92006-09-29 06:00:17 -0700693
694 if (first != NULL) {
Michen Chang63927942008-09-29 17:06:39 -0700695 /* add to list if not in already */
696 for (c = first; c != NULL;
697 c = c->next_to_reclaim) {
698 if (gctx == c)
699 break;
700 }
701 if (c == NULL) {
702 last->next_to_reclaim = gctx;
703 last = gctx;
704 }
djlcb5caa92006-09-29 06:00:17 -0700705 } else {
706 first = gctx;
707 last = gctx;
708 }
709 }
710 }
711
712 (void) rw_unlock(&getent_ctxDB_rwlock);
713
714
715 /*
michen29836b12008-08-04 08:31:06 -0700716 * return all the orphan getent contexts to the pool if not
717 * in use
djlcb5caa92006-09-29 06:00:17 -0700718 */
719 for (gctx = first; gctx; ) {
Michen Chang63927942008-09-29 17:06:39 -0700720 int in_use, num_reclaim_check;
721
722 c = gctx->next_to_reclaim;
723 gctx->next_to_reclaim = NULL;
michen29836b12008-08-04 08:31:06 -0700724 gctx->aborted = 1;
Michen Chang63927942008-09-29 17:06:39 -0700725
michen29836b12008-08-04 08:31:06 -0700726 (void) mutex_lock(&gctx->getent_mutex);
Michen Chang63927942008-09-29 17:06:39 -0700727 num_reclaim_check = gctx->num_reclaim_check++;
728 if (num_reclaim_check > 1)
729 gctx->in_use = 0;
michen29836b12008-08-04 08:31:06 -0700730 in_use = gctx->in_use;
731 (void) mutex_unlock(&gctx->getent_mutex);
Michen Chang63927942008-09-29 17:06:39 -0700732
733 if (in_use == 0) {
734 _NSCD_LOG(NSCD_LOG_GETENT_CTX,
735 NSCD_LOG_LEVEL_DEBUG)
736 (me, "process %d exited, "
737 "freeing getent context = %p\n",
738 gctx->pid, gctx);
739 nssctx.ctx = (struct nss_getent_context *)gctx;
740 nss_endent(NULL, NULL, &nssctx);
michen29836b12008-08-04 08:31:06 -0700741 }
djlcb5caa92006-09-29 06:00:17 -0700742 gctx = c;
743 }
744 first = last = NULL;
djlcb5caa92006-09-29 06:00:17 -0700745 }
746 /*NOTREACHED*/
747 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
748}
749
750static nscd_rc_t
John Levonab618542018-10-08 15:34:11 +0100751_nscd_init_getent_ctx_monitor()
752{
djlcb5caa92006-09-29 06:00:17 -0700753
754 int errnum;
755 char *me = "_nscd_init_getent_ctx_monitor";
756
757 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
758 (me, "initializing the getent context monitor\n");
759
760 /*
761 * the forker nscd does not process getent requests
762 * so no need to monitor orphan getent contexts
763 */
764 if (_whoami == NSCD_FORKER)
765 return (NSCD_SUCCESS);
766
767 /*
768 * start a thread to reclaim unused getent contexts
769 */
770 if (thr_create(NULL, NULL, reclaim_getent_ctx,
John Levonab618542018-10-08 15:34:11 +0100771 NULL, THR_DETACHED, NULL) != 0) {
djlcb5caa92006-09-29 06:00:17 -0700772 errnum = errno;
773 _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_ERROR)
774 (me, "thr_create: %s\n", strerror(errnum));
775 return (NSCD_THREAD_CREATE_ERROR);
776 }
777
778 return (NSCD_SUCCESS);
779}