xref: /titanic_53/usr/src/cmd/nscd/nscd_getentctx.c (revision 978eb14434856052ad78b0b4c626508b7f2e0f3d)
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.
24cb5caa98Sdjl  */
25cb5caa98Sdjl 
26cb5caa98Sdjl #include <stdlib.h>
27cb5caa98Sdjl #include <assert.h>
28cb5caa98Sdjl #include <string.h>
29cb5caa98Sdjl #include <errno.h>
30cb5caa98Sdjl #include <fcntl.h>
31cb5caa98Sdjl #include "nscd_db.h"
32cb5caa98Sdjl #include "nscd_log.h"
33cb5caa98Sdjl #include "nscd_switch.h"
34cb5caa98Sdjl #include "nscd_door.h"
35cb5caa98Sdjl 
36cb5caa98Sdjl extern int		_whoami;
37cb5caa98Sdjl static mutex_t		getent_monitor_mutex = DEFAULTMUTEX;
38cb5caa98Sdjl static int		getent_monitor_started = 0;
39cb5caa98Sdjl 
40cb5caa98Sdjl static rwlock_t		getent_ctxDB_rwlock = DEFAULTRWLOCK;
41cb5caa98Sdjl static nscd_db_t	*getent_ctxDB = NULL;
42cb5caa98Sdjl 
43cb5caa98Sdjl /*
44cb5caa98Sdjl  * internal structure representing a nscd getent context
45cb5caa98Sdjl  */
46cb5caa98Sdjl typedef struct nscd_getent_ctx {
47cb5caa98Sdjl 	int			to_delete; /* this ctx no longer valid */
48cb5caa98Sdjl 	nscd_getent_context_t	*ptr;
49e37190e5Smichen 	nscd_cookie_num_t	cookie_num;
50cb5caa98Sdjl } nscd_getent_ctx_t;
51cb5caa98Sdjl 
52cb5caa98Sdjl /*
53cb5caa98Sdjl  * nscd_getent_context_t list for each nss database. Protected
54cb5caa98Sdjl  * by the readers/writer lock nscd_getent_ctx_lock.
55cb5caa98Sdjl  */
56cb5caa98Sdjl nscd_getent_ctx_base_t **nscd_getent_ctx_base;
57cb5caa98Sdjl static rwlock_t nscd_getent_ctx_base_lock = DEFAULTRWLOCK;
58cb5caa98Sdjl 
59cb5caa98Sdjl extern nscd_db_entry_t *_nscd_walk_db(nscd_db_t *db, void **cookie);
60cb5caa98Sdjl 
61cb5caa98Sdjl static nscd_rc_t _nscd_init_getent_ctx_monitor();
62cb5caa98Sdjl 
63cb5caa98Sdjl /*
64cb5caa98Sdjl  * FUNCTION: _nscd_create_getent_ctxDB
65cb5caa98Sdjl  *
66cb5caa98Sdjl  * Create the internal getent context database to keep track of the
67cb5caa98Sdjl  * getent contexts currently being used.
68cb5caa98Sdjl  */
69cb5caa98Sdjl nscd_db_t *
70cb5caa98Sdjl _nscd_create_getent_ctxDB()
71cb5caa98Sdjl {
72cb5caa98Sdjl 
73cb5caa98Sdjl 	nscd_db_t	*ret;
74cb5caa98Sdjl 
75cb5caa98Sdjl 	(void) rw_wrlock(&getent_ctxDB_rwlock);
76cb5caa98Sdjl 
77cb5caa98Sdjl 	if (getent_ctxDB != NULL) {
78cb5caa98Sdjl 		(void) rw_unlock(&getent_ctxDB_rwlock);
79cb5caa98Sdjl 		return (getent_ctxDB);
80cb5caa98Sdjl 	}
81cb5caa98Sdjl 
82cb5caa98Sdjl 	ret = _nscd_alloc_db(NSCD_DB_SIZE_LARGE);
83cb5caa98Sdjl 
84cb5caa98Sdjl 	if (ret != NULL)
85cb5caa98Sdjl 		getent_ctxDB = ret;
86cb5caa98Sdjl 
87cb5caa98Sdjl 	(void) rw_unlock(&getent_ctxDB_rwlock);
88cb5caa98Sdjl 
89cb5caa98Sdjl 	return (ret);
90cb5caa98Sdjl }
91cb5caa98Sdjl 
92cb5caa98Sdjl /*
93cb5caa98Sdjl  * FUNCTION: _nscd_add_getent_ctx
94cb5caa98Sdjl  *
95cb5caa98Sdjl  * Add a getent context to the internal context database.
96cb5caa98Sdjl  */
97cb5caa98Sdjl static nscd_rc_t
98cb5caa98Sdjl _nscd_add_getent_ctx(
99cb5caa98Sdjl 	nscd_getent_context_t	*ptr,
100e37190e5Smichen 	nscd_cookie_num_t	cookie_num)
101cb5caa98Sdjl {
102cb5caa98Sdjl 	int			size;
10329836b19Smichen 	char			buf[32];
104cb5caa98Sdjl 	nscd_db_entry_t		*db_entry;
105cb5caa98Sdjl 	nscd_getent_ctx_t	*gnctx;
106cb5caa98Sdjl 
107cb5caa98Sdjl 	if (ptr == NULL)
108cb5caa98Sdjl 		return (NSCD_INVALID_ARGUMENT);
109cb5caa98Sdjl 
110e37190e5Smichen 	(void) snprintf(buf, sizeof (buf), "%lld", cookie_num);
111cb5caa98Sdjl 
112cb5caa98Sdjl 	size = sizeof (*gnctx);
113cb5caa98Sdjl 
114cb5caa98Sdjl 	db_entry = _nscd_alloc_db_entry(NSCD_DATA_CTX_ADDR,
115cb5caa98Sdjl 	    (const char *)buf, size, 1, 1);
116cb5caa98Sdjl 	if (db_entry == NULL)
117cb5caa98Sdjl 		return (NSCD_NO_MEMORY);
118cb5caa98Sdjl 
119cb5caa98Sdjl 	gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array);
120cb5caa98Sdjl 	gnctx->ptr = ptr;
121e37190e5Smichen 	gnctx->cookie_num = cookie_num;
122cb5caa98Sdjl 
123cb5caa98Sdjl 	(void) rw_wrlock(&getent_ctxDB_rwlock);
124cb5caa98Sdjl 	(void) _nscd_add_db_entry(getent_ctxDB, buf, db_entry,
125cb5caa98Sdjl 	    NSCD_ADD_DB_ENTRY_FIRST);
126cb5caa98Sdjl 	(void) rw_unlock(&getent_ctxDB_rwlock);
127cb5caa98Sdjl 
128cb5caa98Sdjl 	return (NSCD_SUCCESS);
129cb5caa98Sdjl }
130cb5caa98Sdjl 
131cb5caa98Sdjl /*
132cb5caa98Sdjl  * FUNCTION: _nscd_is_getent_ctx
133cb5caa98Sdjl  *
134cb5caa98Sdjl  * Check to see if a getent context can be found in the internal
135cb5caa98Sdjl  * getent context database.
136cb5caa98Sdjl  */
137cb5caa98Sdjl nscd_getent_context_t *
138cb5caa98Sdjl _nscd_is_getent_ctx(
139e37190e5Smichen 	nscd_cookie_num_t	cookie_num)
140cb5caa98Sdjl {
14129836b19Smichen 	char			ptrstr[32];
142cb5caa98Sdjl 	const nscd_db_entry_t	*db_entry;
143cb5caa98Sdjl 	nscd_getent_context_t	*ret = NULL;
1446392794bSMichen Chang 	char			*me = "_nscd_is_getent_ctx";
145cb5caa98Sdjl 
146e37190e5Smichen 	(void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num);
147cb5caa98Sdjl 
148cb5caa98Sdjl 	(void) rw_rdlock(&getent_ctxDB_rwlock);
149cb5caa98Sdjl 
150cb5caa98Sdjl 	db_entry = _nscd_get_db_entry(getent_ctxDB, NSCD_DATA_CTX_ADDR,
151cb5caa98Sdjl 	    (const char *)ptrstr, NSCD_GET_FIRST_DB_ENTRY, 0);
152cb5caa98Sdjl 
153cb5caa98Sdjl 	if (db_entry != NULL) {
154cb5caa98Sdjl 		nscd_getent_ctx_t *gnctx;
155cb5caa98Sdjl 
156cb5caa98Sdjl 		gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array);
1576392794bSMichen Chang 		_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
1586392794bSMichen Chang 		(me, "getent context %p, cookie# %lld, to_delete %d\n",
1596392794bSMichen Chang 		    gnctx->ptr, gnctx->cookie_num, gnctx->to_delete);
160cb5caa98Sdjl 
161cb5caa98Sdjl 		/*
1626392794bSMichen Chang 		 * If the ctx is not to be deleted and the cookie numbers
163cfed26cbSMichen Chang 		 * match, return the ctx if not aborted and not in use.
164cb5caa98Sdjl 		 * Otherwise return NULL.
165cb5caa98Sdjl 		 */
16629836b19Smichen 		if (gnctx->to_delete == 0 && gnctx->cookie_num == cookie_num) {
167cb5caa98Sdjl 			ret = gnctx->ptr;
16829836b19Smichen 			(void) mutex_lock(&gnctx->ptr->getent_mutex);
16929836b19Smichen 			if (ret->aborted == 1 || ret->in_use == 1)
17029836b19Smichen 				ret = NULL;
17129836b19Smichen 			else
17229836b19Smichen 				ret->in_use = 1;
17329836b19Smichen 			(void) mutex_unlock(&gnctx->ptr->getent_mutex);
17429836b19Smichen 		}
175cb5caa98Sdjl 	}
176cb5caa98Sdjl 
177cb5caa98Sdjl 	(void) rw_unlock(&getent_ctxDB_rwlock);
178cb5caa98Sdjl 
179cb5caa98Sdjl 	return (ret);
180cb5caa98Sdjl }
181cb5caa98Sdjl 
1826392794bSMichen Chang int
1836392794bSMichen Chang _nscd_is_getent_ctx_in_use(
1846392794bSMichen Chang 	nscd_getent_context_t	*ctx)
1856392794bSMichen Chang {
1866392794bSMichen Chang 	int	in_use;
1876392794bSMichen Chang 	char	*me = "_nscd_getent_ctx_in_use";
1886392794bSMichen Chang 
1896392794bSMichen Chang 	(void) mutex_lock(&ctx->getent_mutex);
1906392794bSMichen Chang 
1916392794bSMichen Chang 	_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
1926392794bSMichen Chang 	(me, "in_use = %d, ctx->thr_id = %d, thread id = %d\n",
1936392794bSMichen Chang 	    ctx->in_use, ctx->thr_id, thr_self());
1946392794bSMichen Chang 
1956392794bSMichen Chang 	in_use = ctx->in_use;
1966392794bSMichen Chang 	if (in_use == 1 && ctx->thr_id == thr_self())
1976392794bSMichen Chang 		in_use = 0;
1986392794bSMichen Chang 	(void) mutex_unlock(&ctx->getent_mutex);
1996392794bSMichen Chang 	return (in_use);
2006392794bSMichen Chang }
2016392794bSMichen Chang 
202cb5caa98Sdjl /*
20329836b19Smichen  * FUNCTION: _nscd_free_ctx_if_aborted
20429836b19Smichen  *
20529836b19Smichen  * Check to see if the getent session associated with a getent context had
20629836b19Smichen  * been aborted. If so, return the getent context back to the pool.
20729836b19Smichen  */
20829836b19Smichen void
20929836b19Smichen _nscd_free_ctx_if_aborted(
21029836b19Smichen 	nscd_getent_context_t	*ctx)
21129836b19Smichen {
21229836b19Smichen 	int	aborted;
21329836b19Smichen 	char	*me = "_nscd_free_ctx_if_aborted";
21429836b19Smichen 
21529836b19Smichen 	(void) mutex_lock(&ctx->getent_mutex);
2166392794bSMichen Chang 
2176392794bSMichen Chang 	_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
2186392794bSMichen Chang 	(me, "in_use = %d, aborted = %d\n", ctx->in_use, ctx->aborted);
2196392794bSMichen Chang 
2206392794bSMichen Chang 	if (ctx->in_use != 1) {
2216392794bSMichen Chang 		(void) mutex_unlock(&ctx->getent_mutex);
2226392794bSMichen Chang 		return;
2236392794bSMichen Chang 	}
22429836b19Smichen 	aborted = ctx->aborted;
2256392794bSMichen Chang 	ctx->in_use = 0;
22629836b19Smichen 	(void) mutex_unlock(&ctx->getent_mutex);
22729836b19Smichen 
22829836b19Smichen 	if (aborted == 1) {
22929836b19Smichen 		_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
23029836b19Smichen 		(me, "getent session aborted, return the getent context\n");
23129836b19Smichen 		_nscd_put_getent_ctx(ctx);
23229836b19Smichen 	}
23329836b19Smichen }
23429836b19Smichen 
23529836b19Smichen /*
236cb5caa98Sdjl  * FUNCTION: _nscd_del_getent_ctx
237cb5caa98Sdjl  *
238cb5caa98Sdjl  * Delete a getent context from the internal getent context database.
239cb5caa98Sdjl  */
240cb5caa98Sdjl static void
241cb5caa98Sdjl _nscd_del_getent_ctx(
242cb5caa98Sdjl 	nscd_getent_context_t	*ptr,
243e37190e5Smichen 	nscd_cookie_num_t	cookie_num)
244cb5caa98Sdjl {
24529836b19Smichen 	char			ptrstr[32];
246cb5caa98Sdjl 	nscd_getent_ctx_t	*gnctx;
247cb5caa98Sdjl 	const nscd_db_entry_t	*db_entry;
248cb5caa98Sdjl 
249cb5caa98Sdjl 	if (ptr == NULL)
250cb5caa98Sdjl 		return;
251cb5caa98Sdjl 
252e37190e5Smichen 	(void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie_num);
253cb5caa98Sdjl 
254cb5caa98Sdjl 	(void) rw_rdlock(&getent_ctxDB_rwlock);
255cb5caa98Sdjl 	/*
256cb5caa98Sdjl 	 * first find the db entry and make sure the
257cb5caa98Sdjl 	 * sequence number matched, then delete it from
258cb5caa98Sdjl 	 * the database.
259cb5caa98Sdjl 	 */
260cb5caa98Sdjl 	db_entry = _nscd_get_db_entry(getent_ctxDB,
261cb5caa98Sdjl 	    NSCD_DATA_CTX_ADDR,
262cb5caa98Sdjl 	    (const char *)ptrstr,
263cb5caa98Sdjl 	    NSCD_GET_FIRST_DB_ENTRY, 0);
264cb5caa98Sdjl 	if (db_entry != NULL) {
265cb5caa98Sdjl 		gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array);
266e37190e5Smichen 		if (gnctx->ptr == ptr && gnctx->cookie_num  == cookie_num) {
267cb5caa98Sdjl 
268cb5caa98Sdjl 			(void) rw_unlock(&getent_ctxDB_rwlock);
269cb5caa98Sdjl 			(void) rw_wrlock(&getent_ctxDB_rwlock);
270cb5caa98Sdjl 
271cb5caa98Sdjl 			(void) _nscd_delete_db_entry(getent_ctxDB,
272cb5caa98Sdjl 			    NSCD_DATA_CTX_ADDR,
273cb5caa98Sdjl 			    (const char *)ptrstr,
274cb5caa98Sdjl 			    NSCD_DEL_FIRST_DB_ENTRY, 0);
275cb5caa98Sdjl 		}
276cb5caa98Sdjl 	}
277cb5caa98Sdjl 	(void) rw_unlock(&getent_ctxDB_rwlock);
278cb5caa98Sdjl }
279cb5caa98Sdjl 
280cb5caa98Sdjl static void
281cb5caa98Sdjl _nscd_free_getent_ctx(
282cb5caa98Sdjl 	nscd_getent_context_t	*gnctx)
283cb5caa98Sdjl {
284cb5caa98Sdjl 
285cb5caa98Sdjl 	char			*me = "_nscd_free_getent_ctx";
286cb5caa98Sdjl 
287cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
288cb5caa98Sdjl 	(me, "getent context %p\n", gnctx);
289cb5caa98Sdjl 
290cb5caa98Sdjl 	_nscd_put_nsw_state(gnctx->nsw_state);
291cfed26cbSMichen Chang 
292cfed26cbSMichen Chang 	if (gnctx->base != NULL) {
293cfed26cbSMichen Chang 		/* remove reference to the getent context base */
294cfed26cbSMichen Chang 		_nscd_release((nscd_acc_data_t *)gnctx->base);
295cfed26cbSMichen Chang 		gnctx->base = NULL;
296cfed26cbSMichen Chang 	}
297cfed26cbSMichen Chang 
298e37190e5Smichen 	_nscd_del_getent_ctx(gnctx, gnctx->cookie_num);
299cb5caa98Sdjl 	free(gnctx);
300cb5caa98Sdjl }
301cb5caa98Sdjl 
302cb5caa98Sdjl 
303cb5caa98Sdjl static void
304cb5caa98Sdjl _nscd_free_getent_ctx_base(
305cb5caa98Sdjl 	nscd_acc_data_t		*data)
306cb5caa98Sdjl {
307cb5caa98Sdjl 	nscd_getent_ctx_base_t	*base = (nscd_getent_ctx_base_t *)data;
308cb5caa98Sdjl 	nscd_getent_context_t	*c, *tc;
309cb5caa98Sdjl 	char			*me = "_nscd_free_getent_ctx_base";
310cb5caa98Sdjl 
311cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
312cb5caa98Sdjl 	(me, "getent context base %p\n", base);
313cb5caa98Sdjl 
314cb5caa98Sdjl 	if (base == NULL)
315cb5caa98Sdjl 		return;
316cb5caa98Sdjl 
317cb5caa98Sdjl 	c = base->first;
318cb5caa98Sdjl 	while (c != NULL) {
319cb5caa98Sdjl 		tc = c->next;
320cb5caa98Sdjl 		_nscd_free_getent_ctx(c);
321cb5caa98Sdjl 		c = tc;
322cb5caa98Sdjl 	}
323cb5caa98Sdjl }
324cb5caa98Sdjl 
325cb5caa98Sdjl void
326cb5caa98Sdjl _nscd_free_all_getent_ctx_base()
327cb5caa98Sdjl {
328cb5caa98Sdjl 	nscd_getent_ctx_base_t	*base;
329cb5caa98Sdjl 	int			i;
330cb5caa98Sdjl 	char			*me = "_nscd_free_all_getent_ctx_base";
331cb5caa98Sdjl 
332cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
333cb5caa98Sdjl 	(me, "entering ..\n");
334cb5caa98Sdjl 
335cb5caa98Sdjl 	(void) rw_wrlock(&nscd_getent_ctx_base_lock);
336cb5caa98Sdjl 
337cb5caa98Sdjl 	for (i = 0; i < NSCD_NUM_DB; i++) {
338cb5caa98Sdjl 
339cb5caa98Sdjl 		base = nscd_getent_ctx_base[i];
340cb5caa98Sdjl 		if (base == NULL)
341cb5caa98Sdjl 			continue;
342cb5caa98Sdjl 
343cb5caa98Sdjl 		nscd_getent_ctx_base[i] = (nscd_getent_ctx_base_t *)
344cb5caa98Sdjl 		    _nscd_set((nscd_acc_data_t *)base, NULL);
345cb5caa98Sdjl 	}
346cb5caa98Sdjl 	(void) rw_unlock(&nscd_getent_ctx_base_lock);
347cb5caa98Sdjl }
348cb5caa98Sdjl 
349cb5caa98Sdjl static nscd_getent_context_t *
350cb5caa98Sdjl _nscd_create_getent_ctx(
351cb5caa98Sdjl 	nscd_nsw_params_t	*params)
352cb5caa98Sdjl {
353cb5caa98Sdjl 	nscd_getent_context_t	*gnctx;
354cb5caa98Sdjl 	nss_db_root_t		db_root;
355cb5caa98Sdjl 	char			*me = "_nscd_create_getent_ctx";
356cb5caa98Sdjl 
357cb5caa98Sdjl 	gnctx = calloc(1, sizeof (nscd_getent_context_t));
358cb5caa98Sdjl 	if (gnctx == NULL)
359cb5caa98Sdjl 		return (NULL);
360cb5caa98Sdjl 	else {
361cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
362cb5caa98Sdjl 		(me, "getent context allocated %p\n", gnctx);
363cb5caa98Sdjl 	}
364cb5caa98Sdjl 
365cb5caa98Sdjl 	gnctx->dbi = params->dbi;
366e37190e5Smichen 	gnctx->cookie_num = _nscd_get_cookie_num();
3679f590749Smichen 	gnctx->pid = -1;
36829836b19Smichen 	(void) mutex_init(&gnctx->getent_mutex, USYNC_THREAD, NULL);
369cb5caa98Sdjl 
370cb5caa98Sdjl 	if (_nscd_get_nsw_state(&db_root, params) != NSCD_SUCCESS) {
371cb5caa98Sdjl 		free(gnctx);
372cb5caa98Sdjl 		return (NULL);
373cb5caa98Sdjl 	}
374cb5caa98Sdjl 	gnctx->nsw_state = (nscd_nsw_state_t *)db_root.s;
375cb5caa98Sdjl 	/* this is a nsw_state used for getent processing */
376cb5caa98Sdjl 	gnctx->nsw_state->getent = 1;
377cb5caa98Sdjl 
378cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
379cb5caa98Sdjl 	(me, "got nsw_state %p\n", gnctx->nsw_state);
380cb5caa98Sdjl 
381cb5caa98Sdjl 	return (gnctx);
382cb5caa98Sdjl }
383cb5caa98Sdjl 
384cb5caa98Sdjl 
385cb5caa98Sdjl nscd_rc_t
386cb5caa98Sdjl _nscd_get_getent_ctx(
387cb5caa98Sdjl 	nss_getent_t		*contextpp,
388cb5caa98Sdjl 	nscd_nsw_params_t	*params)
389cb5caa98Sdjl {
390cb5caa98Sdjl 
391cb5caa98Sdjl 	nscd_getent_context_t	*c;
392cb5caa98Sdjl 	nscd_getent_ctx_base_t	*base, *tmp;
393cb5caa98Sdjl 	nscd_rc_t		rc;
394cb5caa98Sdjl 	char			*me = "_nscd_get_getent_ctx";
395cb5caa98Sdjl 
396cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
397cb5caa98Sdjl 	(me, "entering ...\n");
398cb5caa98Sdjl 
399cb5caa98Sdjl 	(void) rw_rdlock(&nscd_getent_ctx_base_lock);
400cb5caa98Sdjl 	base = nscd_getent_ctx_base[params->dbi];
401cb5caa98Sdjl 	(void) rw_unlock(&nscd_getent_ctx_base_lock);
402cb5caa98Sdjl 	assert(base != NULL);
403cb5caa98Sdjl 
404cb5caa98Sdjl 	/*
405cb5caa98Sdjl 	 * If the context list is not empty, return the first one
406cb5caa98Sdjl 	 * on the list. Otherwise, create and return a new one if
407*978eb144SJulian Pullen 	 * limit is not reached. If limit is reached return an error
408*978eb144SJulian Pullen 	 * so that the client can perform the enumeration.
409cb5caa98Sdjl 	 */
410cb5caa98Sdjl 	tmp = (nscd_getent_ctx_base_t *)_nscd_mutex_lock(
411cb5caa98Sdjl 	    (nscd_acc_data_t *)base);
412cb5caa98Sdjl 	assert(base == tmp);
413cb5caa98Sdjl 	if (base->first == NULL) {
414*978eb144SJulian Pullen 		if (base->num_getent_ctx >= base->max_getent_ctx) {
415*978eb144SJulian Pullen 			/* run out of contexts */
416cb5caa98Sdjl 
417cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_GETENT_CTX,
418cb5caa98Sdjl 			    NSCD_LOG_LEVEL_DEBUG)
419*978eb144SJulian Pullen 			(me, "run out of getent ctxs\n");
420cb5caa98Sdjl 
421*978eb144SJulian Pullen 			_nscd_mutex_unlock((nscd_acc_data_t *)base);
422*978eb144SJulian Pullen 			return (NSCD_CREATE_GETENT_CTX_FAILED);
423cb5caa98Sdjl 		} else {
424cb5caa98Sdjl 			base->first = _nscd_create_getent_ctx(params);
425cfed26cbSMichen Chang 			if (base->first != NULL)
426cb5caa98Sdjl 				base->num_getent_ctx++;
427cfed26cbSMichen Chang 			else {
428cfed26cbSMichen Chang 				/* not able to create a getent ctx */
429cb5caa98Sdjl 
430cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_GETENT_CTX,
431cb5caa98Sdjl 				    NSCD_LOG_LEVEL_ERROR)
432cb5caa98Sdjl 				(me, "create getent ctx failed\n");
433cb5caa98Sdjl 
434cb5caa98Sdjl 				_nscd_mutex_unlock((nscd_acc_data_t *)base);
435cb5caa98Sdjl 				return (NSCD_CREATE_GETENT_CTX_FAILED);
436cb5caa98Sdjl 			}
437cb5caa98Sdjl 
438cb5caa98Sdjl 			_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
439cb5caa98Sdjl 			(me, "got a new getent ctx %p\n", base->first);
440cb5caa98Sdjl 		}
441cb5caa98Sdjl 	}
442cb5caa98Sdjl 
443cb5caa98Sdjl 	assert(base->first != NULL);
444cb5caa98Sdjl 
445cb5caa98Sdjl 	c = base->first;
446cb5caa98Sdjl 	base->first = c->next;
447cb5caa98Sdjl 	c->next = NULL;
448cb5caa98Sdjl 	c->seq_num = 1;
4496392794bSMichen Chang 	c->cookie_num = _nscd_get_cookie_num();
45029836b19Smichen 	c->in_use = 1;
4516392794bSMichen Chang 	c->thr_id = thr_self();
452cb5caa98Sdjl 
453cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
454cb5caa98Sdjl 	(me, "got a getent ctx %p\n", c);
455cb5caa98Sdjl 
456cfed26cbSMichen Chang 	/*
457cfed26cbSMichen Chang 	 * reference count the getent context base bfore handing out
458cfed26cbSMichen Chang 	 * the getent context
459cfed26cbSMichen Chang 	 */
460cfed26cbSMichen Chang 	c->base = (nscd_getent_ctx_base_t *)
461cfed26cbSMichen Chang 	    _nscd_get((nscd_acc_data_t *)base);
462cfed26cbSMichen Chang 
463cb5caa98Sdjl 	_nscd_mutex_unlock((nscd_acc_data_t *)base);
464cb5caa98Sdjl 
465cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
466e37190e5Smichen 	(me, "adding new ctx %p, cookie # = %lld\n", c, c->cookie_num);
467cb5caa98Sdjl 
468e37190e5Smichen 	if ((rc = _nscd_add_getent_ctx(c, c->cookie_num)) != NSCD_SUCCESS) {
469cb5caa98Sdjl 		_nscd_put_getent_ctx(c);
470cb5caa98Sdjl 		return (rc);
471cb5caa98Sdjl 	}
472cb5caa98Sdjl 	contextpp->ctx = (struct nss_getent_context *)c;
473cb5caa98Sdjl 
474cb5caa98Sdjl 	/* start monitor and reclaim orphan getent context */
475cb5caa98Sdjl 	if (getent_monitor_started == 0) {
476cb5caa98Sdjl 		(void) mutex_lock(&getent_monitor_mutex);
477cb5caa98Sdjl 		if (getent_monitor_started == 0) {
478cb5caa98Sdjl 			getent_monitor_started = 1;
479cb5caa98Sdjl 			(void) _nscd_init_getent_ctx_monitor();
480cb5caa98Sdjl 		}
481cb5caa98Sdjl 		(void) mutex_unlock(&getent_monitor_mutex);
482cb5caa98Sdjl 	}
483cb5caa98Sdjl 
484cb5caa98Sdjl 	return (NSCD_SUCCESS);
485cb5caa98Sdjl }
486cb5caa98Sdjl 
487cb5caa98Sdjl void
488cb5caa98Sdjl _nscd_put_getent_ctx(
489cb5caa98Sdjl 	nscd_getent_context_t	*gnctx)
490cb5caa98Sdjl {
491cb5caa98Sdjl 
492cb5caa98Sdjl 	nscd_getent_ctx_base_t	*base;
493cb5caa98Sdjl 	char			*me = "_nscd_put_getent_ctx";
494cb5caa98Sdjl 
495cb5caa98Sdjl 	base = gnctx->base;
496cb5caa98Sdjl 
497cfed26cbSMichen Chang 	/* if context base is gone or no longer current, free this context */
498cb5caa98Sdjl 	if ((_nscd_mutex_lock((nscd_acc_data_t *)base)) == NULL) {
499cb5caa98Sdjl 		_nscd_free_getent_ctx(gnctx);
500cb5caa98Sdjl 		return;
501cb5caa98Sdjl 	}
502cb5caa98Sdjl 
503cb5caa98Sdjl 	if (base->first != NULL) {
504cb5caa98Sdjl 		gnctx->next = base->first;
505cb5caa98Sdjl 		base->first = gnctx;
506cb5caa98Sdjl 	} else
507cb5caa98Sdjl 		base->first = gnctx;
508cb5caa98Sdjl 
509cb5caa98Sdjl 	/* put back the db state */
510cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
511cb5caa98Sdjl 	(me, "putting back nsw state %p\n", gnctx->nsw_state);
512cb5caa98Sdjl 
513cb5caa98Sdjl 	/* this nsw_state is no longer used for getent processing */
5146392794bSMichen Chang 	if (gnctx->nsw_state != NULL) {
515cb5caa98Sdjl 		gnctx->nsw_state->getent = 0;
516cb5caa98Sdjl 		_nscd_put_nsw_state(gnctx->nsw_state);
517cb5caa98Sdjl 		gnctx->nsw_state = NULL;
5186392794bSMichen Chang 	}
519cb5caa98Sdjl 
52029836b19Smichen 	gnctx->aborted = 0;
52129836b19Smichen 	gnctx->in_use = 0;
5226392794bSMichen Chang 	gnctx->thr_id = (thread_t)-1;
523e37190e5Smichen 	_nscd_del_getent_ctx(gnctx, gnctx->cookie_num);
524cb5caa98Sdjl 
525cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
526e37190e5Smichen 	(me, "ctx (%p, cookie # = %lld) removed from getent ctx DB\n",
527e37190e5Smichen 	    gnctx, gnctx->cookie_num);
528cb5caa98Sdjl 
5296392794bSMichen Chang 	gnctx->seq_num = 0;
5306392794bSMichen Chang 	gnctx->cookie_num = 0;
5316392794bSMichen Chang 	gnctx->pid = -1;
5326392794bSMichen Chang 	gnctx->thr_id = (thread_t)-1;
5336392794bSMichen Chang 	gnctx->n_src = 0;
5346392794bSMichen Chang 	gnctx->be = NULL;
5356392794bSMichen Chang 
536cfed26cbSMichen Chang 	/* remove reference to the getent context base */
537cfed26cbSMichen Chang 	_nscd_release((nscd_acc_data_t *)base);
538cfed26cbSMichen Chang 	gnctx->base = NULL;
539cfed26cbSMichen Chang 
540cb5caa98Sdjl 	_nscd_mutex_unlock((nscd_acc_data_t *)base);
541cb5caa98Sdjl }
542cb5caa98Sdjl 
543cb5caa98Sdjl nscd_rc_t
544cb5caa98Sdjl _nscd_init_getent_ctx_base(
545cb5caa98Sdjl 	int			dbi,
546cb5caa98Sdjl 	int			lock)
547cb5caa98Sdjl {
548cb5caa98Sdjl 	nscd_getent_ctx_base_t	*base = NULL;
549cb5caa98Sdjl 	char			*me = "_nscd_init_getent_ctx_base";
550cb5caa98Sdjl 
551cb5caa98Sdjl 	if (lock)
552cb5caa98Sdjl 		(void) rw_rdlock(&nscd_getent_ctx_base_lock);
553cb5caa98Sdjl 
554cb5caa98Sdjl 	base = (nscd_getent_ctx_base_t *)_nscd_alloc(
555cb5caa98Sdjl 	    NSCD_DATA_GETENT_CTX_BASE,
556cb5caa98Sdjl 	    sizeof (nscd_getent_ctx_base_t),
557cb5caa98Sdjl 	    _nscd_free_getent_ctx_base,
558cb5caa98Sdjl 	    NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND);
559cb5caa98Sdjl 
560cb5caa98Sdjl 	if (base == NULL) {
561cb5caa98Sdjl 		if (lock)
562cb5caa98Sdjl 			(void) rw_unlock(&nscd_getent_ctx_base_lock);
563cb5caa98Sdjl 		return (NSCD_NO_MEMORY);
564cb5caa98Sdjl 	}
565cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
566cb5caa98Sdjl 	(me, "base %p allocated\n", base);
567cb5caa98Sdjl 
568cb5caa98Sdjl 	/*
569cb5caa98Sdjl 	 * initialize and activate the new getent_ctx base
570cb5caa98Sdjl 	 */
571cb5caa98Sdjl 	base->dbi = dbi;
572cb5caa98Sdjl 	base->max_getent_ctx = NSCD_SW_CFG(dbi).max_getent_ctx_per_db;
573cb5caa98Sdjl 	nscd_getent_ctx_base[dbi] =
574cb5caa98Sdjl 	    (nscd_getent_ctx_base_t *)_nscd_set(
575cb5caa98Sdjl 	    (nscd_acc_data_t *)nscd_getent_ctx_base[dbi],
576cb5caa98Sdjl 	    (nscd_acc_data_t *)base);
577cb5caa98Sdjl 
578cb5caa98Sdjl 	if (lock)
579cb5caa98Sdjl 		(void) rw_unlock(&nscd_getent_ctx_base_lock);
580cb5caa98Sdjl 
581cb5caa98Sdjl 	return (NSCD_SUCCESS);
582cb5caa98Sdjl }
583cb5caa98Sdjl 
584cb5caa98Sdjl nscd_rc_t
585cb5caa98Sdjl _nscd_init_all_getent_ctx_base()
586cb5caa98Sdjl {
587cb5caa98Sdjl 	int			i;
588cb5caa98Sdjl 	nscd_rc_t		rc;
589cb5caa98Sdjl 	char			*me = "_nscd_init_all_getent_ctx_base";
590cb5caa98Sdjl 
591cb5caa98Sdjl 	(void) rw_wrlock(&nscd_getent_ctx_base_lock);
592cb5caa98Sdjl 
593cb5caa98Sdjl 	for (i = 0; i < NSCD_NUM_DB; i++) {
594cb5caa98Sdjl 
595cb5caa98Sdjl 		rc = _nscd_init_getent_ctx_base(i, 0);
596cb5caa98Sdjl 
597cb5caa98Sdjl 		if (rc != NSCD_SUCCESS) {
598cb5caa98Sdjl 			(void) rw_unlock(&nscd_getent_ctx_base_lock);
599cb5caa98Sdjl 			return (rc);
600cb5caa98Sdjl 		}
601cb5caa98Sdjl 	}
602cb5caa98Sdjl 
603cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
604cb5caa98Sdjl 	(me, "all getent context base initialized\n");
605cb5caa98Sdjl 
606cb5caa98Sdjl 	(void) rw_unlock(&nscd_getent_ctx_base_lock);
607cb5caa98Sdjl 
608cb5caa98Sdjl 	return (NSCD_SUCCESS);
609cb5caa98Sdjl }
610cb5caa98Sdjl nscd_rc_t
611cb5caa98Sdjl _nscd_alloc_getent_ctx_base()
612cb5caa98Sdjl {
613cb5caa98Sdjl 
614cb5caa98Sdjl 	(void) rw_wrlock(&nscd_getent_ctx_base_lock);
615cb5caa98Sdjl 
616cb5caa98Sdjl 	nscd_getent_ctx_base = calloc(NSCD_NUM_DB,
617cb5caa98Sdjl 	    sizeof (nscd_getent_ctx_base_t *));
618cb5caa98Sdjl 	if (nscd_getent_ctx_base == NULL) {
619cb5caa98Sdjl 		(void) rw_unlock(&nscd_getent_ctx_base_lock);
620cb5caa98Sdjl 		return (NSCD_NO_MEMORY);
621cb5caa98Sdjl 	}
622cb5caa98Sdjl 
623cb5caa98Sdjl 	(void) rw_unlock(&nscd_getent_ctx_base_lock);
624cb5caa98Sdjl 
625cb5caa98Sdjl 	return (NSCD_SUCCESS);
626cb5caa98Sdjl }
627cb5caa98Sdjl 
628cb5caa98Sdjl static int
629cb5caa98Sdjl process_exited(pid_t pid)
630cb5caa98Sdjl {
631cb5caa98Sdjl 	char	pname[PATH_MAX];
632cb5caa98Sdjl 	int	fd;
633cb5caa98Sdjl 
634cb5caa98Sdjl 	(void) snprintf(pname, sizeof (pname), "/proc/%d/psinfo", pid);
635cb5caa98Sdjl 	if ((fd = open(pname, O_RDONLY)) == -1)
636cb5caa98Sdjl 		return (1);
637cb5caa98Sdjl 	else {
638cb5caa98Sdjl 		(void) close(fd);
639cb5caa98Sdjl 		return (0);
640cb5caa98Sdjl 	}
641cb5caa98Sdjl }
642cb5caa98Sdjl 
643cb5caa98Sdjl /*
644cb5caa98Sdjl  * FUNCTION: reclaim_getent_ctx
645cb5caa98Sdjl  */
646cb5caa98Sdjl /*ARGSUSED*/
647cb5caa98Sdjl static void *
648cb5caa98Sdjl reclaim_getent_ctx(void *arg)
649cb5caa98Sdjl {
650cb5caa98Sdjl 	void			*cookie = NULL;
651cb5caa98Sdjl 	nscd_db_entry_t		*ep;
652cb5caa98Sdjl 	nscd_getent_ctx_t	*ctx;
653cb5caa98Sdjl 	nscd_getent_context_t	*gctx, *c;
654cb5caa98Sdjl 	nscd_getent_context_t	*first = NULL, *last = NULL;
6556392794bSMichen Chang 	nss_getent_t		nssctx = { 0 };
656cb5caa98Sdjl 	char			*me = "reclaim_getent_ctx";
657cb5caa98Sdjl 
658cb5caa98Sdjl 	/*CONSTCOND*/
659cb5caa98Sdjl 	while (1) {
660cb5caa98Sdjl 
6619f590749Smichen 		(void) sleep(60);
6629f590749Smichen 
663cb5caa98Sdjl 		(void) rw_rdlock(&getent_ctxDB_rwlock);
664cb5caa98Sdjl 
665cb5caa98Sdjl 		for (ep = _nscd_walk_db(getent_ctxDB, &cookie); ep != NULL;
666cb5caa98Sdjl 		    ep = _nscd_walk_db(getent_ctxDB, &cookie)) {
667cb5caa98Sdjl 
668cb5caa98Sdjl 			ctx = (nscd_getent_ctx_t *)*(ep->data_array);
669cb5caa98Sdjl 
670cb5caa98Sdjl 			gctx = ctx->ptr;
671cb5caa98Sdjl 
672cb5caa98Sdjl 			/*
673cb5caa98Sdjl 			 * if the client process, which did the setent,
674cb5caa98Sdjl 			 * exited, add the context to the orphan list
675cb5caa98Sdjl 			 */
676cb5caa98Sdjl 			if (gctx->pid != -1 && process_exited(gctx->pid)) {
677cb5caa98Sdjl 
678cb5caa98Sdjl 				_NSCD_LOG(NSCD_LOG_GETENT_CTX,
679cb5caa98Sdjl 				    NSCD_LOG_LEVEL_DEBUG)
680cb5caa98Sdjl 				(me, "process  %d exited, "
681cb5caa98Sdjl 				    "getent context = %p, "
682e37190e5Smichen 				    "db index = %d, cookie # = %lld, "
683cb5caa98Sdjl 				    "sequence # = %lld\n",
684cb5caa98Sdjl 				    gctx->pid, gctx, gctx->dbi,
685e37190e5Smichen 				    gctx->cookie_num, gctx->seq_num);
686cb5caa98Sdjl 
687cb5caa98Sdjl 				if (first != NULL) {
6886392794bSMichen Chang 					/* add to list if not in already */
6896392794bSMichen Chang 					for (c = first; c != NULL;
6906392794bSMichen Chang 					    c = c->next_to_reclaim) {
6916392794bSMichen Chang 						if (gctx == c)
6926392794bSMichen Chang 							break;
6936392794bSMichen Chang 					}
6946392794bSMichen Chang 					if (c == NULL) {
6956392794bSMichen Chang 						last->next_to_reclaim = gctx;
696cb5caa98Sdjl 						last = gctx;
6976392794bSMichen Chang 					}
698cb5caa98Sdjl 				} else {
699cb5caa98Sdjl 					first = gctx;
700cb5caa98Sdjl 					last = gctx;
701cb5caa98Sdjl 				}
702cb5caa98Sdjl 			}
703cb5caa98Sdjl 		}
704cb5caa98Sdjl 
705cb5caa98Sdjl 		(void) rw_unlock(&getent_ctxDB_rwlock);
706cb5caa98Sdjl 
707cb5caa98Sdjl 
708cb5caa98Sdjl 		/*
70929836b19Smichen 		 * return all the orphan getent contexts to the pool if not
71029836b19Smichen 		 * in use
711cb5caa98Sdjl 		 */
712cb5caa98Sdjl 		for (gctx = first; gctx; ) {
7136392794bSMichen Chang 			int in_use, num_reclaim_check;
7146392794bSMichen Chang 
7156392794bSMichen Chang 			c = gctx->next_to_reclaim;
7166392794bSMichen Chang 			gctx->next_to_reclaim = NULL;
71729836b19Smichen 			gctx->aborted = 1;
7186392794bSMichen Chang 
71929836b19Smichen 			(void) mutex_lock(&gctx->getent_mutex);
7206392794bSMichen Chang 			num_reclaim_check = gctx->num_reclaim_check++;
7216392794bSMichen Chang 			if (num_reclaim_check > 1)
7226392794bSMichen Chang 				gctx->in_use = 0;
72329836b19Smichen 			in_use = gctx->in_use;
72429836b19Smichen 			(void) mutex_unlock(&gctx->getent_mutex);
7256392794bSMichen Chang 
7266392794bSMichen Chang 			if (in_use == 0) {
7276392794bSMichen Chang 				_NSCD_LOG(NSCD_LOG_GETENT_CTX,
7286392794bSMichen Chang 				    NSCD_LOG_LEVEL_DEBUG)
7296392794bSMichen Chang 				(me, "process  %d exited, "
7306392794bSMichen Chang 				    "freeing getent context = %p\n",
7316392794bSMichen Chang 				    gctx->pid, gctx);
7326392794bSMichen Chang 				nssctx.ctx = (struct nss_getent_context *)gctx;
7336392794bSMichen Chang 				nss_endent(NULL, NULL, &nssctx);
73429836b19Smichen 			}
735cb5caa98Sdjl 			gctx = c;
736cb5caa98Sdjl 		}
737cb5caa98Sdjl 		first = last = NULL;
738cb5caa98Sdjl 	}
739cb5caa98Sdjl 	/*NOTREACHED*/
740cb5caa98Sdjl 	/*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
741cb5caa98Sdjl }
742cb5caa98Sdjl 
743cb5caa98Sdjl static nscd_rc_t
744cb5caa98Sdjl _nscd_init_getent_ctx_monitor() {
745cb5caa98Sdjl 
746cb5caa98Sdjl 	int	errnum;
747cb5caa98Sdjl 	char	*me = "_nscd_init_getent_ctx_monitor";
748cb5caa98Sdjl 
749cb5caa98Sdjl 	_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG)
750cb5caa98Sdjl 	(me, "initializing the getent context monitor\n");
751cb5caa98Sdjl 
752cb5caa98Sdjl 	/*
753cb5caa98Sdjl 	 * the forker nscd does not process getent requests
754cb5caa98Sdjl 	 * so no need to monitor orphan getent contexts
755cb5caa98Sdjl 	 */
756cb5caa98Sdjl 	if (_whoami == NSCD_FORKER)
757cb5caa98Sdjl 		return (NSCD_SUCCESS);
758cb5caa98Sdjl 
759cb5caa98Sdjl 	/*
760cb5caa98Sdjl 	 * start a thread to reclaim unused getent contexts
761cb5caa98Sdjl 	 */
762cb5caa98Sdjl 	if (thr_create(NULL, NULL, reclaim_getent_ctx,
763cb5caa98Sdjl 		NULL, THR_DETACHED, NULL) != 0) {
764cb5caa98Sdjl 		errnum = errno;
765cb5caa98Sdjl 		_NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_ERROR)
766cb5caa98Sdjl 		(me, "thr_create: %s\n", strerror(errnum));
767cb5caa98Sdjl 		return (NSCD_THREAD_CREATE_ERROR);
768cb5caa98Sdjl 	}
769cb5caa98Sdjl 
770cb5caa98Sdjl 	return (NSCD_SUCCESS);
771cb5caa98Sdjl }
772