xref: /titanic_50/usr/src/cmd/nscd/nscd_getentctx.c (revision cb5caa98562cf06753163f558cbcfe30b8f4673a)
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