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 /*
22cfed26cbSMichen Chang * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23cb5caa98Sdjl * Use is subject to license terms.
24ab618543SJohn Levon *
25ab618543SJohn Levon * Copyright 2018 Joyent, Inc.
26cb5caa98Sdjl */
27cb5caa98Sdjl
289e293969SRichard Lowe #include <sys/ccompile.h>
299e293969SRichard Lowe
30cb5caa98Sdjl #include <stdlib.h>
31cb5caa98Sdjl #include <assert.h>
32cb5caa98Sdjl #include <string.h>
33cb5caa98Sdjl #include <errno.h>
34cb5caa98Sdjl #include <fcntl.h>
359e293969SRichard Lowe
36cb5caa98Sdjl #include "nscd_db.h"
37cb5caa98Sdjl #include "nscd_log.h"
38cb5caa98Sdjl #include "nscd_switch.h"
39cb5caa98Sdjl #include "nscd_door.h"
40cb5caa98Sdjl
41cb5caa98Sdjl extern int _whoami;
42cb5caa98Sdjl static mutex_t getent_monitor_mutex = DEFAULTMUTEX;
43cb5caa98Sdjl static int getent_monitor_started = 0;
44cb5caa98Sdjl
45cb5caa98Sdjl static rwlock_t getent_ctxDB_rwlock = DEFAULTRWLOCK;
46cb5caa98Sdjl static nscd_db_t *getent_ctxDB = NULL;
47cb5caa98Sdjl
48cb5caa98Sdjl /*
49cb5caa98Sdjl * internal structure representing a nscd getent context
50cb5caa98Sdjl */
51cb5caa98Sdjl typedef struct nscd_getent_ctx {
52cb5caa98Sdjl int to_delete; /* this ctx no longer valid */
53cb5caa98Sdjl nscd_getent_context_t *ptr;
54e37190e5Smichen nscd_cookie_num_t cookie_num;
55cb5caa98Sdjl } nscd_getent_ctx_t;
56cb5caa98Sdjl
57cb5caa98Sdjl /*
58cb5caa98Sdjl * nscd_getent_context_t list for each nss database. Protected
59cb5caa98Sdjl * by the readers/writer lock nscd_getent_ctx_lock.
60cb5caa98Sdjl */
61cb5caa98Sdjl nscd_getent_ctx_base_t **nscd_getent_ctx_base;
62cb5caa98Sdjl static rwlock_t nscd_getent_ctx_base_lock = DEFAULTRWLOCK;
63cb5caa98Sdjl
64cb5caa98Sdjl extern nscd_db_entry_t *_nscd_walk_db(nscd_db_t *db, void **cookie);
65cb5caa98Sdjl
66cb5caa98Sdjl static nscd_rc_t _nscd_init_getent_ctx_monitor();
67cb5caa98Sdjl
68cb5caa98Sdjl /*
69cb5caa98Sdjl * FUNCTION: _nscd_create_getent_ctxDB
70cb5caa98Sdjl *
71cb5caa98Sdjl * Create the internal getent context database to keep track of the
72cb5caa98Sdjl * getent contexts currently being used.
73cb5caa98Sdjl */
74cb5caa98Sdjl nscd_db_t *
_nscd_create_getent_ctxDB()75cb5caa98Sdjl _nscd_create_getent_ctxDB()
76cb5caa98Sdjl {
77cb5caa98Sdjl
78cb5caa98Sdjl nscd_db_t *ret;
79cb5caa98Sdjl
80cb5caa98Sdjl (void) rw_wrlock(&getent_ctxDB_rwlock);
81cb5caa98Sdjl
82cb5caa98Sdjl if (getent_ctxDB != NULL) {
83cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock);
84cb5caa98Sdjl return (getent_ctxDB);
85cb5caa98Sdjl }
86cb5caa98Sdjl
87cb5caa98Sdjl ret = _nscd_alloc_db(NSCD_DB_SIZE_LARGE);
88cb5caa98Sdjl
89cb5caa98Sdjl if (ret != NULL)
90cb5caa98Sdjl getent_ctxDB = ret;
91cb5caa98Sdjl
92cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock);
93cb5caa98Sdjl
94cb5caa98Sdjl return (ret);
95cb5caa98Sdjl }
96cb5caa98Sdjl
97cb5caa98Sdjl /*
98cb5caa98Sdjl * FUNCTION: _nscd_add_getent_ctx
99cb5caa98Sdjl *
100cb5caa98Sdjl * Add a getent context to the internal context database.
101cb5caa98Sdjl */
102cb5caa98Sdjl static nscd_rc_t
_nscd_add_getent_ctx(nscd_getent_context_t * ptr,nscd_cookie_num_t cookie_num)103cb5caa98Sdjl _nscd_add_getent_ctx(
104cb5caa98Sdjl nscd_getent_context_t *ptr,
105e37190e5Smichen nscd_cookie_num_t cookie_num)
106cb5caa98Sdjl {
107cb5caa98Sdjl int size;
10829836b19Smichen char buf[32];
109cb5caa98Sdjl nscd_db_entry_t *db_entry;
110cb5caa98Sdjl nscd_getent_ctx_t *gnctx;
111cb5caa98Sdjl
112cb5caa98Sdjl if (ptr == NULL)
113cb5caa98Sdjl return (NSCD_INVALID_ARGUMENT);
114cb5caa98Sdjl
115e37190e5Smichen (void) snprintf(buf, sizeof (buf), "%lld", cookie_num);
116cb5caa98Sdjl
117cb5caa98Sdjl size = sizeof (*gnctx);
118cb5caa98Sdjl
119cb5caa98Sdjl db_entry = _nscd_alloc_db_entry(NSCD_DATA_CTX_ADDR,
12029836b19Smichen (const char *)buf, size, 1, 1);
121cb5caa98Sdjl if (db_entry == NULL)
122cb5caa98Sdjl return (NSCD_NO_MEMORY);
123cb5caa98Sdjl
124cb5caa98Sdjl gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array);
125cb5caa98Sdjl gnctx->ptr = ptr;
126e37190e5Smichen gnctx->cookie_num = cookie_num;
127cb5caa98Sdjl
128cb5caa98Sdjl (void) rw_wrlock(&getent_ctxDB_rwlock);
129cb5caa98Sdjl (void) _nscd_add_db_entry(getent_ctxDB, buf, db_entry,
13029836b19Smichen NSCD_ADD_DB_ENTRY_FIRST);
131cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock);
132cb5caa98Sdjl
133cb5caa98Sdjl return (NSCD_SUCCESS);
134cb5caa98Sdjl }
135cb5caa98Sdjl
136cb5caa98Sdjl /*
137cb5caa98Sdjl * FUNCTION: _nscd_is_getent_ctx
138cb5caa98Sdjl *
139cb5caa98Sdjl * Check to see if a getent context can be found in the internal
140cb5caa98Sdjl * getent context database.
141cb5caa98Sdjl */
142cb5caa98Sdjl nscd_getent_context_t *
_nscd_is_getent_ctx(nscd_cookie_num_t cookie_num)143cb5caa98Sdjl _nscd_is_getent_ctx(
144e37190e5Smichen nscd_cookie_num_t cookie_num)
145cb5caa98Sdjl {
14629836b19Smichen char ptrstr[32];
147cb5caa98Sdjl const nscd_db_entry_t *db_entry;
148cb5caa98Sdjl nscd_getent_context_t *ret = NULL;
1496392794bSMichen Chang char *me = "_nscd_is_getent_ctx";
150cb5caa98Sdjl
151e37190e5Smichen (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num);
152cb5caa98Sdjl
153cb5caa98Sdjl (void) rw_rdlock(&getent_ctxDB_rwlock);
154cb5caa98Sdjl
155cb5caa98Sdjl db_entry = _nscd_get_db_entry(getent_ctxDB, NSCD_DATA_CTX_ADDR,
15629836b19Smichen (const char *)ptrstr, NSCD_GET_FIRST_DB_ENTRY, 0);
157cb5caa98Sdjl
158cb5caa98Sdjl if (db_entry != NULL) {
159cb5caa98Sdjl nscd_getent_ctx_t *gnctx;
160cb5caa98Sdjl
161cb5caa98Sdjl gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array);
1626392794bSMichen Chang _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
1636392794bSMichen Chang (me, "getent context %p, cookie# %lld, to_delete %d\n",
1646392794bSMichen Chang gnctx->ptr, gnctx->cookie_num, gnctx->to_delete);
165cb5caa98Sdjl
166cb5caa98Sdjl /*
1676392794bSMichen Chang * If the ctx is not to be deleted and the cookie numbers
168cfed26cbSMichen Chang * match, return the ctx if not aborted and not in use.
169cb5caa98Sdjl * Otherwise return NULL.
170cb5caa98Sdjl */
17129836b19Smichen if (gnctx->to_delete == 0 && gnctx->cookie_num == cookie_num) {
172cb5caa98Sdjl ret = gnctx->ptr;
17329836b19Smichen (void) mutex_lock(&gnctx->ptr->getent_mutex);
17429836b19Smichen if (ret->aborted == 1 || ret->in_use == 1)
17529836b19Smichen ret = NULL;
17629836b19Smichen else
17729836b19Smichen ret->in_use = 1;
17829836b19Smichen (void) mutex_unlock(&gnctx->ptr->getent_mutex);
17929836b19Smichen }
180cb5caa98Sdjl }
181cb5caa98Sdjl
182cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock);
183cb5caa98Sdjl
184cb5caa98Sdjl return (ret);
185cb5caa98Sdjl }
186cb5caa98Sdjl
1876392794bSMichen Chang int
_nscd_is_getent_ctx_in_use(nscd_getent_context_t * ctx)1886392794bSMichen Chang _nscd_is_getent_ctx_in_use(
1896392794bSMichen Chang nscd_getent_context_t *ctx)
1906392794bSMichen Chang {
1916392794bSMichen Chang int in_use;
1926392794bSMichen Chang char *me = "_nscd_getent_ctx_in_use";
1936392794bSMichen Chang
1946392794bSMichen Chang (void) mutex_lock(&ctx->getent_mutex);
1956392794bSMichen Chang
1966392794bSMichen Chang _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
1976392794bSMichen Chang (me, "in_use = %d, ctx->thr_id = %d, thread id = %d\n",
1986392794bSMichen Chang ctx->in_use, ctx->thr_id, thr_self());
1996392794bSMichen Chang
2006392794bSMichen Chang in_use = ctx->in_use;
2016392794bSMichen Chang if (in_use == 1 && ctx->thr_id == thr_self())
2026392794bSMichen Chang in_use = 0;
2036392794bSMichen Chang (void) mutex_unlock(&ctx->getent_mutex);
2046392794bSMichen Chang return (in_use);
2056392794bSMichen Chang }
2066392794bSMichen Chang
20729836b19Smichen /*
20829836b19Smichen * FUNCTION: _nscd_free_ctx_if_aborted
20929836b19Smichen *
21029836b19Smichen * Check to see if the getent session associated with a getent context had
21129836b19Smichen * been aborted. If so, return the getent context back to the pool.
21229836b19Smichen */
21329836b19Smichen void
_nscd_free_ctx_if_aborted(nscd_getent_context_t * ctx)21429836b19Smichen _nscd_free_ctx_if_aborted(
21529836b19Smichen nscd_getent_context_t *ctx)
21629836b19Smichen {
21729836b19Smichen int aborted;
21829836b19Smichen char *me = "_nscd_free_ctx_if_aborted";
21929836b19Smichen
22029836b19Smichen (void) mutex_lock(&ctx->getent_mutex);
2216392794bSMichen Chang
2226392794bSMichen Chang _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
2236392794bSMichen Chang (me, "in_use = %d, aborted = %d\n", ctx->in_use, ctx->aborted);
2246392794bSMichen Chang
2256392794bSMichen Chang if (ctx->in_use != 1) {
2266392794bSMichen Chang (void) mutex_unlock(&ctx->getent_mutex);
2276392794bSMichen Chang return;
2286392794bSMichen Chang }
22929836b19Smichen aborted = ctx->aborted;
2306392794bSMichen Chang ctx->in_use = 0;
23129836b19Smichen (void) mutex_unlock(&ctx->getent_mutex);
23229836b19Smichen
23329836b19Smichen if (aborted == 1) {
23429836b19Smichen _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
23529836b19Smichen (me, "getent session aborted, return the getent context\n");
23629836b19Smichen _nscd_put_getent_ctx(ctx);
23729836b19Smichen }
23829836b19Smichen }
23929836b19Smichen
240cb5caa98Sdjl /*
241cb5caa98Sdjl * FUNCTION: _nscd_del_getent_ctx
242cb5caa98Sdjl *
243cb5caa98Sdjl * Delete a getent context from the internal getent context database.
244cb5caa98Sdjl */
245cb5caa98Sdjl static void
_nscd_del_getent_ctx(nscd_getent_context_t * ptr,nscd_cookie_num_t cookie_num)246cb5caa98Sdjl _nscd_del_getent_ctx(
247cb5caa98Sdjl nscd_getent_context_t *ptr,
248e37190e5Smichen nscd_cookie_num_t cookie_num)
249cb5caa98Sdjl {
25029836b19Smichen char ptrstr[32];
251cb5caa98Sdjl nscd_getent_ctx_t *gnctx;
252cb5caa98Sdjl const nscd_db_entry_t *db_entry;
253cb5caa98Sdjl
254cb5caa98Sdjl if (ptr == NULL)
255cb5caa98Sdjl return;
256cb5caa98Sdjl
257e37190e5Smichen (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num);
258cb5caa98Sdjl
259cb5caa98Sdjl (void) rw_rdlock(&getent_ctxDB_rwlock);
260cb5caa98Sdjl /*
261cb5caa98Sdjl * first find the db entry and make sure the
262cb5caa98Sdjl * sequence number matched, then delete it from
263cb5caa98Sdjl * the database.
264cb5caa98Sdjl */
265cb5caa98Sdjl db_entry = _nscd_get_db_entry(getent_ctxDB,
26629836b19Smichen NSCD_DATA_CTX_ADDR,
26729836b19Smichen (const char *)ptrstr,
26829836b19Smichen NSCD_GET_FIRST_DB_ENTRY, 0);
269cb5caa98Sdjl if (db_entry != NULL) {
270cb5caa98Sdjl gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array);
271e37190e5Smichen if (gnctx->ptr == ptr && gnctx->cookie_num == cookie_num) {
272cb5caa98Sdjl
273cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock);
274cb5caa98Sdjl (void) rw_wrlock(&getent_ctxDB_rwlock);
275cb5caa98Sdjl
276cb5caa98Sdjl (void) _nscd_delete_db_entry(getent_ctxDB,
27729836b19Smichen NSCD_DATA_CTX_ADDR,
27829836b19Smichen (const char *)ptrstr,
27929836b19Smichen NSCD_DEL_FIRST_DB_ENTRY, 0);
280cb5caa98Sdjl }
281cb5caa98Sdjl }
282cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock);
283cb5caa98Sdjl }
284cb5caa98Sdjl
285cb5caa98Sdjl static void
_nscd_free_getent_ctx(nscd_getent_context_t * gnctx)286cb5caa98Sdjl _nscd_free_getent_ctx(
287cb5caa98Sdjl nscd_getent_context_t *gnctx)
288cb5caa98Sdjl {
289cb5caa98Sdjl
290cb5caa98Sdjl char *me = "_nscd_free_getent_ctx";
291cb5caa98Sdjl
292cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
293cb5caa98Sdjl (me, "getent context %p\n", gnctx);
294cb5caa98Sdjl
295cb5caa98Sdjl _nscd_put_nsw_state(gnctx->nsw_state);
296cfed26cbSMichen Chang
297cfed26cbSMichen Chang if (gnctx->base != NULL) {
298cfed26cbSMichen Chang /* remove reference to the getent context base */
299cfed26cbSMichen Chang _nscd_release((nscd_acc_data_t *)gnctx->base);
300cfed26cbSMichen Chang gnctx->base = NULL;
301cfed26cbSMichen Chang }
302cfed26cbSMichen Chang
303e37190e5Smichen _nscd_del_getent_ctx(gnctx, gnctx->cookie_num);
304cb5caa98Sdjl free(gnctx);
305cb5caa98Sdjl }
306cb5caa98Sdjl
307cb5caa98Sdjl
308cb5caa98Sdjl static void
_nscd_free_getent_ctx_base(nscd_acc_data_t * data)309cb5caa98Sdjl _nscd_free_getent_ctx_base(
310cb5caa98Sdjl nscd_acc_data_t *data)
311cb5caa98Sdjl {
312cb5caa98Sdjl nscd_getent_ctx_base_t *base = (nscd_getent_ctx_base_t *)data;
313cb5caa98Sdjl nscd_getent_context_t *c, *tc;
314cb5caa98Sdjl char *me = "_nscd_free_getent_ctx_base";
315cb5caa98Sdjl
316cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
317cb5caa98Sdjl (me, "getent context base %p\n", base);
318cb5caa98Sdjl
319cb5caa98Sdjl if (base == NULL)
320cb5caa98Sdjl return;
321cb5caa98Sdjl
322cb5caa98Sdjl c = base->first;
323cb5caa98Sdjl while (c != NULL) {
324cb5caa98Sdjl tc = c->next;
325cb5caa98Sdjl _nscd_free_getent_ctx(c);
326cb5caa98Sdjl c = tc;
327cb5caa98Sdjl }
328cb5caa98Sdjl }
329cb5caa98Sdjl
330cb5caa98Sdjl void
_nscd_free_all_getent_ctx_base()331cb5caa98Sdjl _nscd_free_all_getent_ctx_base()
332cb5caa98Sdjl {
333cb5caa98Sdjl nscd_getent_ctx_base_t *base;
334cb5caa98Sdjl int i;
335cb5caa98Sdjl char *me = "_nscd_free_all_getent_ctx_base";
336cb5caa98Sdjl
337cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
338cb5caa98Sdjl (me, "entering ..\n");
339cb5caa98Sdjl
340cb5caa98Sdjl (void) rw_wrlock(&nscd_getent_ctx_base_lock);
341cb5caa98Sdjl
342cb5caa98Sdjl for (i = 0; i < NSCD_NUM_DB; i++) {
343cb5caa98Sdjl
344cb5caa98Sdjl base = nscd_getent_ctx_base[i];
345cb5caa98Sdjl if (base == NULL)
346cb5caa98Sdjl continue;
347cb5caa98Sdjl
348cb5caa98Sdjl nscd_getent_ctx_base[i] = (nscd_getent_ctx_base_t *)
34929836b19Smichen _nscd_set((nscd_acc_data_t *)base, NULL);
350cb5caa98Sdjl }
351cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock);
352cb5caa98Sdjl }
353cb5caa98Sdjl
354cb5caa98Sdjl static nscd_getent_context_t *
_nscd_create_getent_ctx(nscd_nsw_params_t * params)355cb5caa98Sdjl _nscd_create_getent_ctx(
356cb5caa98Sdjl nscd_nsw_params_t *params)
357cb5caa98Sdjl {
358cb5caa98Sdjl nscd_getent_context_t *gnctx;
359cb5caa98Sdjl nss_db_root_t db_root;
360cb5caa98Sdjl char *me = "_nscd_create_getent_ctx";
361cb5caa98Sdjl
362cb5caa98Sdjl gnctx = calloc(1, sizeof (nscd_getent_context_t));
363cb5caa98Sdjl if (gnctx == NULL)
364cb5caa98Sdjl return (NULL);
365cb5caa98Sdjl else {
366cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
367cb5caa98Sdjl (me, "getent context allocated %p\n", gnctx);
368cb5caa98Sdjl }
369cb5caa98Sdjl
370cb5caa98Sdjl gnctx->dbi = params->dbi;
371e37190e5Smichen gnctx->cookie_num = _nscd_get_cookie_num();
3729f590749Smichen gnctx->pid = -1;
37329836b19Smichen (void) mutex_init(&gnctx->getent_mutex, USYNC_THREAD, NULL);
374cb5caa98Sdjl
375cb5caa98Sdjl if (_nscd_get_nsw_state(&db_root, params) != NSCD_SUCCESS) {
376cb5caa98Sdjl free(gnctx);
377cb5caa98Sdjl return (NULL);
378cb5caa98Sdjl }
379cb5caa98Sdjl gnctx->nsw_state = (nscd_nsw_state_t *)db_root.s;
380cb5caa98Sdjl /* this is a nsw_state used for getent processing */
381cb5caa98Sdjl gnctx->nsw_state->getent = 1;
382cb5caa98Sdjl
383cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
384cb5caa98Sdjl (me, "got nsw_state %p\n", gnctx->nsw_state);
385cb5caa98Sdjl
386cb5caa98Sdjl return (gnctx);
387cb5caa98Sdjl }
388cb5caa98Sdjl
389cb5caa98Sdjl
390cb5caa98Sdjl nscd_rc_t
_nscd_get_getent_ctx(nss_getent_t * contextpp,nscd_nsw_params_t * params)391cb5caa98Sdjl _nscd_get_getent_ctx(
392cb5caa98Sdjl nss_getent_t *contextpp,
393cb5caa98Sdjl nscd_nsw_params_t *params)
394cb5caa98Sdjl {
395cb5caa98Sdjl
396cb5caa98Sdjl nscd_getent_context_t *c;
397cb5caa98Sdjl nscd_getent_ctx_base_t *base, *tmp;
398cb5caa98Sdjl nscd_rc_t rc;
399cb5caa98Sdjl char *me = "_nscd_get_getent_ctx";
400cb5caa98Sdjl
401cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
402cb5caa98Sdjl (me, "entering ...\n");
403cb5caa98Sdjl
404cb5caa98Sdjl (void) rw_rdlock(&nscd_getent_ctx_base_lock);
405cb5caa98Sdjl base = nscd_getent_ctx_base[params->dbi];
406cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock);
407cb5caa98Sdjl assert(base != NULL);
408cb5caa98Sdjl
409cb5caa98Sdjl /*
410cb5caa98Sdjl * If the context list is not empty, return the first one
411cb5caa98Sdjl * on the list. Otherwise, create and return a new one if
412978eb144SJulian Pullen * limit is not reached. If limit is reached return an error
413978eb144SJulian Pullen * so that the client can perform the enumeration.
414cb5caa98Sdjl */
415cb5caa98Sdjl tmp = (nscd_getent_ctx_base_t *)_nscd_mutex_lock(
41629836b19Smichen (nscd_acc_data_t *)base);
417cb5caa98Sdjl assert(base == tmp);
418cb5caa98Sdjl if (base->first == NULL) {
419978eb144SJulian Pullen if (base->num_getent_ctx >= base->max_getent_ctx) {
420978eb144SJulian Pullen /* run out of contexts */
421cb5caa98Sdjl
422978eb144SJulian Pullen _NSCD_LOG(NSCD_LOG_GETENT_CTX,
423978eb144SJulian Pullen NSCD_LOG_LEVEL_DEBUG)
424978eb144SJulian Pullen (me, "run out of getent ctxs\n");
425cb5caa98Sdjl
426978eb144SJulian Pullen _nscd_mutex_unlock((nscd_acc_data_t *)base);
427978eb144SJulian Pullen return (NSCD_CREATE_GETENT_CTX_FAILED);
428cb5caa98Sdjl } else {
429cb5caa98Sdjl base->first = _nscd_create_getent_ctx(params);
430cfed26cbSMichen Chang if (base->first != NULL)
431cb5caa98Sdjl base->num_getent_ctx++;
432cfed26cbSMichen Chang else {
433cfed26cbSMichen Chang /* not able to create a getent ctx */
434cb5caa98Sdjl
435cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX,
43629836b19Smichen NSCD_LOG_LEVEL_ERROR)
437cb5caa98Sdjl (me, "create getent ctx failed\n");
438cb5caa98Sdjl
439cb5caa98Sdjl _nscd_mutex_unlock((nscd_acc_data_t *)base);
440cb5caa98Sdjl return (NSCD_CREATE_GETENT_CTX_FAILED);
441cb5caa98Sdjl }
442cb5caa98Sdjl
443cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
444cb5caa98Sdjl (me, "got a new getent ctx %p\n", base->first);
445cb5caa98Sdjl }
446cb5caa98Sdjl }
447cb5caa98Sdjl
448cb5caa98Sdjl assert(base->first != NULL);
449cb5caa98Sdjl
450cb5caa98Sdjl c = base->first;
451cb5caa98Sdjl base->first = c->next;
452cb5caa98Sdjl c->next = NULL;
453cb5caa98Sdjl c->seq_num = 1;
4546392794bSMichen Chang c->cookie_num = _nscd_get_cookie_num();
45529836b19Smichen c->in_use = 1;
4566392794bSMichen Chang c->thr_id = thr_self();
457cb5caa98Sdjl
458cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
459cb5caa98Sdjl (me, "got a getent ctx %p\n", c);
460cb5caa98Sdjl
461cfed26cbSMichen Chang /*
462cfed26cbSMichen Chang * reference count the getent context base bfore handing out
463cfed26cbSMichen Chang * the getent context
464cfed26cbSMichen Chang */
465cfed26cbSMichen Chang c->base = (nscd_getent_ctx_base_t *)
466cfed26cbSMichen Chang _nscd_get((nscd_acc_data_t *)base);
467cfed26cbSMichen Chang
468cb5caa98Sdjl _nscd_mutex_unlock((nscd_acc_data_t *)base);
469cb5caa98Sdjl
470cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
471e37190e5Smichen (me, "adding new ctx %p, cookie # = %lld\n", c, c->cookie_num);
472cb5caa98Sdjl
473e37190e5Smichen if ((rc = _nscd_add_getent_ctx(c, c->cookie_num)) != NSCD_SUCCESS) {
474cb5caa98Sdjl _nscd_put_getent_ctx(c);
475cb5caa98Sdjl return (rc);
476cb5caa98Sdjl }
477cb5caa98Sdjl contextpp->ctx = (struct nss_getent_context *)c;
478cb5caa98Sdjl
479cb5caa98Sdjl /* start monitor and reclaim orphan getent context */
480cb5caa98Sdjl if (getent_monitor_started == 0) {
481cb5caa98Sdjl (void) mutex_lock(&getent_monitor_mutex);
482cb5caa98Sdjl if (getent_monitor_started == 0) {
483cb5caa98Sdjl getent_monitor_started = 1;
484cb5caa98Sdjl (void) _nscd_init_getent_ctx_monitor();
485cb5caa98Sdjl }
486cb5caa98Sdjl (void) mutex_unlock(&getent_monitor_mutex);
487cb5caa98Sdjl }
488cb5caa98Sdjl
489cb5caa98Sdjl return (NSCD_SUCCESS);
490cb5caa98Sdjl }
491cb5caa98Sdjl
492cb5caa98Sdjl void
_nscd_put_getent_ctx(nscd_getent_context_t * gnctx)493cb5caa98Sdjl _nscd_put_getent_ctx(
494cb5caa98Sdjl nscd_getent_context_t *gnctx)
495cb5caa98Sdjl {
496cb5caa98Sdjl
497cb5caa98Sdjl nscd_getent_ctx_base_t *base;
498cb5caa98Sdjl char *me = "_nscd_put_getent_ctx";
499cb5caa98Sdjl
500cb5caa98Sdjl base = gnctx->base;
501cb5caa98Sdjl
502cfed26cbSMichen Chang /* if context base is gone or no longer current, free this context */
503cb5caa98Sdjl if ((_nscd_mutex_lock((nscd_acc_data_t *)base)) == NULL) {
504cb5caa98Sdjl _nscd_free_getent_ctx(gnctx);
505cb5caa98Sdjl return;
506cb5caa98Sdjl }
507cb5caa98Sdjl
508cb5caa98Sdjl if (base->first != NULL) {
509cb5caa98Sdjl gnctx->next = base->first;
510cb5caa98Sdjl base->first = gnctx;
511cb5caa98Sdjl } else
512cb5caa98Sdjl base->first = gnctx;
513cb5caa98Sdjl
514cb5caa98Sdjl /* put back the db state */
515cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
516cb5caa98Sdjl (me, "putting back nsw state %p\n", gnctx->nsw_state);
517cb5caa98Sdjl
518cb5caa98Sdjl /* this nsw_state is no longer used for getent processing */
5196392794bSMichen Chang if (gnctx->nsw_state != NULL) {
520cb5caa98Sdjl gnctx->nsw_state->getent = 0;
5216392794bSMichen Chang _nscd_put_nsw_state(gnctx->nsw_state);
5226392794bSMichen Chang gnctx->nsw_state = NULL;
5236392794bSMichen Chang }
524cb5caa98Sdjl
52529836b19Smichen gnctx->aborted = 0;
52629836b19Smichen gnctx->in_use = 0;
5276392794bSMichen Chang gnctx->thr_id = (thread_t)-1;
528e37190e5Smichen _nscd_del_getent_ctx(gnctx, gnctx->cookie_num);
529cb5caa98Sdjl
530cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
531e37190e5Smichen (me, "ctx (%p, cookie # = %lld) removed from getent ctx DB\n",
53229836b19Smichen gnctx, gnctx->cookie_num);
533cb5caa98Sdjl
5346392794bSMichen Chang gnctx->seq_num = 0;
5356392794bSMichen Chang gnctx->cookie_num = 0;
5366392794bSMichen Chang gnctx->pid = -1;
5376392794bSMichen Chang gnctx->thr_id = (thread_t)-1;
5386392794bSMichen Chang gnctx->n_src = 0;
5396392794bSMichen Chang gnctx->be = NULL;
5406392794bSMichen Chang
541cfed26cbSMichen Chang /* remove reference to the getent context base */
542cfed26cbSMichen Chang _nscd_release((nscd_acc_data_t *)base);
543cfed26cbSMichen Chang gnctx->base = NULL;
544cfed26cbSMichen Chang
545cb5caa98Sdjl _nscd_mutex_unlock((nscd_acc_data_t *)base);
546cb5caa98Sdjl }
547cb5caa98Sdjl
548cb5caa98Sdjl nscd_rc_t
_nscd_init_getent_ctx_base(int dbi,int lock)549cb5caa98Sdjl _nscd_init_getent_ctx_base(
550cb5caa98Sdjl int dbi,
551cb5caa98Sdjl int lock)
552cb5caa98Sdjl {
553cb5caa98Sdjl nscd_getent_ctx_base_t *base = NULL;
554cb5caa98Sdjl char *me = "_nscd_init_getent_ctx_base";
555cb5caa98Sdjl
556cb5caa98Sdjl if (lock)
557cb5caa98Sdjl (void) rw_rdlock(&nscd_getent_ctx_base_lock);
558cb5caa98Sdjl
559cb5caa98Sdjl base = (nscd_getent_ctx_base_t *)_nscd_alloc(
56029836b19Smichen NSCD_DATA_GETENT_CTX_BASE,
56129836b19Smichen sizeof (nscd_getent_ctx_base_t),
56229836b19Smichen _nscd_free_getent_ctx_base,
56329836b19Smichen NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND);
564cb5caa98Sdjl
565cb5caa98Sdjl if (base == NULL) {
566cb5caa98Sdjl if (lock)
567cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock);
568cb5caa98Sdjl return (NSCD_NO_MEMORY);
569cb5caa98Sdjl }
570cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
571cb5caa98Sdjl (me, "base %p allocated\n", base);
572cb5caa98Sdjl
573cb5caa98Sdjl /*
574cb5caa98Sdjl * initialize and activate the new getent_ctx base
575cb5caa98Sdjl */
576cb5caa98Sdjl base->dbi = dbi;
577cb5caa98Sdjl base->max_getent_ctx = NSCD_SW_CFG(dbi).max_getent_ctx_per_db;
578cb5caa98Sdjl nscd_getent_ctx_base[dbi] =
57929836b19Smichen (nscd_getent_ctx_base_t *)_nscd_set(
58029836b19Smichen (nscd_acc_data_t *)nscd_getent_ctx_base[dbi],
58129836b19Smichen (nscd_acc_data_t *)base);
582cb5caa98Sdjl
583cb5caa98Sdjl if (lock)
584cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock);
585cb5caa98Sdjl
586cb5caa98Sdjl return (NSCD_SUCCESS);
587cb5caa98Sdjl }
588cb5caa98Sdjl
589cb5caa98Sdjl nscd_rc_t
_nscd_init_all_getent_ctx_base()590cb5caa98Sdjl _nscd_init_all_getent_ctx_base()
591cb5caa98Sdjl {
592cb5caa98Sdjl int i;
593cb5caa98Sdjl nscd_rc_t rc;
594cb5caa98Sdjl char *me = "_nscd_init_all_getent_ctx_base";
595cb5caa98Sdjl
596cb5caa98Sdjl (void) rw_wrlock(&nscd_getent_ctx_base_lock);
597cb5caa98Sdjl
598cb5caa98Sdjl for (i = 0; i < NSCD_NUM_DB; i++) {
599cb5caa98Sdjl
600cb5caa98Sdjl rc = _nscd_init_getent_ctx_base(i, 0);
601cb5caa98Sdjl
602cb5caa98Sdjl if (rc != NSCD_SUCCESS) {
603cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock);
604cb5caa98Sdjl return (rc);
605cb5caa98Sdjl }
606cb5caa98Sdjl }
607cb5caa98Sdjl
608cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
609cb5caa98Sdjl (me, "all getent context base initialized\n");
610cb5caa98Sdjl
611cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock);
612cb5caa98Sdjl
613cb5caa98Sdjl return (NSCD_SUCCESS);
614cb5caa98Sdjl }
615cb5caa98Sdjl nscd_rc_t
_nscd_alloc_getent_ctx_base()616cb5caa98Sdjl _nscd_alloc_getent_ctx_base()
617cb5caa98Sdjl {
618cb5caa98Sdjl
619cb5caa98Sdjl (void) rw_wrlock(&nscd_getent_ctx_base_lock);
620cb5caa98Sdjl
621cb5caa98Sdjl nscd_getent_ctx_base = calloc(NSCD_NUM_DB,
62229836b19Smichen sizeof (nscd_getent_ctx_base_t *));
623cb5caa98Sdjl if (nscd_getent_ctx_base == NULL) {
624cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock);
625cb5caa98Sdjl return (NSCD_NO_MEMORY);
626cb5caa98Sdjl }
627cb5caa98Sdjl
628cb5caa98Sdjl (void) rw_unlock(&nscd_getent_ctx_base_lock);
629cb5caa98Sdjl
630cb5caa98Sdjl return (NSCD_SUCCESS);
631cb5caa98Sdjl }
632cb5caa98Sdjl
633cb5caa98Sdjl static int
process_exited(pid_t pid)634cb5caa98Sdjl process_exited(pid_t pid)
635cb5caa98Sdjl {
636cb5caa98Sdjl char pname[PATH_MAX];
637cb5caa98Sdjl int fd;
638cb5caa98Sdjl
639cb5caa98Sdjl (void) snprintf(pname, sizeof (pname), "/proc/%d/psinfo", pid);
640cb5caa98Sdjl if ((fd = open(pname, O_RDONLY)) == -1)
641cb5caa98Sdjl return (1);
642cb5caa98Sdjl else {
643cb5caa98Sdjl (void) close(fd);
644cb5caa98Sdjl return (0);
645cb5caa98Sdjl }
646cb5caa98Sdjl }
647cb5caa98Sdjl
648cb5caa98Sdjl /*
649cb5caa98Sdjl * FUNCTION: reclaim_getent_ctx
650cb5caa98Sdjl */
651cb5caa98Sdjl /*ARGSUSED*/
6529e293969SRichard Lowe static void * __NORETURN
reclaim_getent_ctx(void * arg)653cb5caa98Sdjl reclaim_getent_ctx(void *arg)
654cb5caa98Sdjl {
655cb5caa98Sdjl void *cookie = NULL;
656cb5caa98Sdjl nscd_db_entry_t *ep;
657cb5caa98Sdjl nscd_getent_ctx_t *ctx;
658cb5caa98Sdjl nscd_getent_context_t *gctx, *c;
659cb5caa98Sdjl nscd_getent_context_t *first = NULL, *last = NULL;
6606392794bSMichen Chang nss_getent_t nssctx = { 0 };
661cb5caa98Sdjl char *me = "reclaim_getent_ctx";
662cb5caa98Sdjl
663ab618543SJohn Levon (void) thr_setname(thr_self(), me);
664ab618543SJohn Levon
665cb5caa98Sdjl /*CONSTCOND*/
666cb5caa98Sdjl while (1) {
667cb5caa98Sdjl
6689f590749Smichen (void) sleep(60);
6699f590749Smichen
670cb5caa98Sdjl (void) rw_rdlock(&getent_ctxDB_rwlock);
671cb5caa98Sdjl
672cb5caa98Sdjl for (ep = _nscd_walk_db(getent_ctxDB, &cookie); ep != NULL;
67329836b19Smichen ep = _nscd_walk_db(getent_ctxDB, &cookie)) {
674cb5caa98Sdjl
675cb5caa98Sdjl ctx = (nscd_getent_ctx_t *)*(ep->data_array);
676cb5caa98Sdjl
677cb5caa98Sdjl gctx = ctx->ptr;
678cb5caa98Sdjl
679cb5caa98Sdjl /*
680cb5caa98Sdjl * if the client process, which did the setent,
681cb5caa98Sdjl * exited, add the context to the orphan list
682cb5caa98Sdjl */
683cb5caa98Sdjl if (gctx->pid != -1 && process_exited(gctx->pid)) {
684cb5caa98Sdjl
685cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX,
68629836b19Smichen NSCD_LOG_LEVEL_DEBUG)
687cb5caa98Sdjl (me, "process %d exited, "
68829836b19Smichen "getent context = %p, "
68929836b19Smichen "db index = %d, cookie # = %lld, "
69029836b19Smichen "sequence # = %lld\n",
69129836b19Smichen gctx->pid, gctx, gctx->dbi,
69229836b19Smichen gctx->cookie_num, gctx->seq_num);
693cb5caa98Sdjl
694cb5caa98Sdjl if (first != NULL) {
6956392794bSMichen Chang /* add to list if not in already */
6966392794bSMichen Chang for (c = first; c != NULL;
6976392794bSMichen Chang c = c->next_to_reclaim) {
6986392794bSMichen Chang if (gctx == c)
6996392794bSMichen Chang break;
7006392794bSMichen Chang }
7016392794bSMichen Chang if (c == NULL) {
7026392794bSMichen Chang last->next_to_reclaim = gctx;
7036392794bSMichen Chang last = gctx;
7046392794bSMichen Chang }
705cb5caa98Sdjl } else {
706cb5caa98Sdjl first = gctx;
707cb5caa98Sdjl last = gctx;
708cb5caa98Sdjl }
709cb5caa98Sdjl }
710cb5caa98Sdjl }
711cb5caa98Sdjl
712cb5caa98Sdjl (void) rw_unlock(&getent_ctxDB_rwlock);
713cb5caa98Sdjl
714cb5caa98Sdjl
715cb5caa98Sdjl /*
71629836b19Smichen * return all the orphan getent contexts to the pool if not
71729836b19Smichen * in use
718cb5caa98Sdjl */
719cb5caa98Sdjl for (gctx = first; gctx; ) {
7206392794bSMichen Chang int in_use, num_reclaim_check;
7216392794bSMichen Chang
7226392794bSMichen Chang c = gctx->next_to_reclaim;
7236392794bSMichen Chang gctx->next_to_reclaim = NULL;
72429836b19Smichen gctx->aborted = 1;
7256392794bSMichen Chang
72629836b19Smichen (void) mutex_lock(&gctx->getent_mutex);
7276392794bSMichen Chang num_reclaim_check = gctx->num_reclaim_check++;
7286392794bSMichen Chang if (num_reclaim_check > 1)
7296392794bSMichen Chang gctx->in_use = 0;
73029836b19Smichen in_use = gctx->in_use;
73129836b19Smichen (void) mutex_unlock(&gctx->getent_mutex);
7326392794bSMichen Chang
7336392794bSMichen Chang if (in_use == 0) {
7346392794bSMichen Chang _NSCD_LOG(NSCD_LOG_GETENT_CTX,
7356392794bSMichen Chang NSCD_LOG_LEVEL_DEBUG)
7366392794bSMichen Chang (me, "process %d exited, "
7376392794bSMichen Chang "freeing getent context = %p\n",
7386392794bSMichen Chang gctx->pid, gctx);
7396392794bSMichen Chang nssctx.ctx = (struct nss_getent_context *)gctx;
7406392794bSMichen Chang nss_endent(NULL, NULL, &nssctx);
74129836b19Smichen }
742cb5caa98Sdjl gctx = c;
743cb5caa98Sdjl }
744cb5caa98Sdjl first = last = NULL;
745cb5caa98Sdjl }
746cb5caa98Sdjl /*NOTREACHED*/
747cb5caa98Sdjl /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
748cb5caa98Sdjl }
749cb5caa98Sdjl
750cb5caa98Sdjl static nscd_rc_t
_nscd_init_getent_ctx_monitor()751ab618543SJohn Levon _nscd_init_getent_ctx_monitor()
752ab618543SJohn Levon {
753cb5caa98Sdjl
754cb5caa98Sdjl int errnum;
755cb5caa98Sdjl char *me = "_nscd_init_getent_ctx_monitor";
756cb5caa98Sdjl
757cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
758cb5caa98Sdjl (me, "initializing the getent context monitor\n");
759cb5caa98Sdjl
760cb5caa98Sdjl /*
761cb5caa98Sdjl * the forker nscd does not process getent requests
762cb5caa98Sdjl * so no need to monitor orphan getent contexts
763cb5caa98Sdjl */
764cb5caa98Sdjl if (_whoami == NSCD_FORKER)
765cb5caa98Sdjl return (NSCD_SUCCESS);
766cb5caa98Sdjl
767cb5caa98Sdjl /*
768cb5caa98Sdjl * start a thread to reclaim unused getent contexts
769cb5caa98Sdjl */
770*fa845c5dSToomas Soome if (thr_create(NULL, 0, reclaim_getent_ctx,
771ab618543SJohn Levon NULL, THR_DETACHED, NULL) != 0) {
772cb5caa98Sdjl errnum = errno;
773cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_ERROR)
774cb5caa98Sdjl (me, "thr_create: %s\n", strerror(errnum));
775cb5caa98Sdjl return (NSCD_THREAD_CREATE_ERROR);
776cb5caa98Sdjl }
777cb5caa98Sdjl
778cb5caa98Sdjl return (NSCD_SUCCESS);
779cb5caa98Sdjl }
780