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