xref: /illumos-gate/usr/src/cmd/nscd/nscd_nswstate.c (revision e753f464d28e02e23aa93bd7d51d39fc56f79897)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <string.h>
30 #include "nscd_switch.h"
31 #include "nscd_log.h"
32 
33 /*
34  * nscd_nsw_state_t list for each nss database. Protected
35  * by the readers/writer lock nscd_nsw_state_base_lock.
36  */
37 nscd_nsw_state_base_t **nscd_nsw_state_base;
38 static rwlock_t nscd_nsw_state_base_lock = DEFAULTRWLOCK;
39 
40 static void
41 _nscd_free_nsw_state(
42 	nscd_nsw_state_t	*s)
43 {
44 
45 	int			i;
46 	char			*me = "_nscd_free_nsw_state";
47 
48 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
49 	(me, "freeing nsw state = %p\n", s);
50 
51 	if (s == NULL)
52 		return;
53 
54 	if (s->nsw_cfg_p != NULL)
55 		/*
56 		 * an nsw state without base does not reference
57 		 * count the nsw config data (ie not using a
58 		 * shared one), so the one created for it should
59 		 * be freed
60 		 */
61 		if ((*s->nsw_cfg_p)->nobase != 1)
62 			_nscd_release((nscd_acc_data_t *)s->nsw_cfg_p);
63 		else
64 			(void) _nscd_set((nscd_acc_data_t *)s->nsw_cfg_p, NULL);
65 
66 	if (s->be_db_pp != NULL) {
67 		for (i = 0; i < s->max_src; i++) {
68 			if (s->be_db_pp[i] == NULL)
69 				continue;
70 			_nscd_release((nscd_acc_data_t *)s->be_db_pp[i]);
71 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
72 			(me, "release db be ptr %p\n", s->be_db_pp[i]);
73 		}
74 		free(s->be_db_pp);
75 	}
76 
77 	if (s->be != NULL) {
78 		for (i = 0; i < s->max_src; i++) {
79 			if (s->be[i] == NULL)
80 				continue;
81 			if (s->getent == 1)
82 				(void) NSS_INVOKE_DBOP(s->be[i],
83 				    NSS_DBOP_ENDENT, 0);
84 			(void) NSS_INVOKE_DBOP(s->be[i],
85 			    NSS_DBOP_DESTRUCTOR, 0);
86 		}
87 		free(s->be);
88 	}
89 
90 	if (s->be_constr != NULL)
91 		free(s->be_constr);
92 
93 	if (s->be_version_p != NULL)
94 		free(s->be_version_p);
95 
96 	/* remove reference to the nsw state base */
97 	if (s->base != NULL) {
98 		_nscd_release((nscd_acc_data_t *)s->base);
99 		s->base = NULL;
100 	}
101 
102 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
103 	(me, "nsw state %p freed \n", s);
104 
105 	free(s);
106 }
107 
108 static void
109 _nscd_free_nsw_state_base(
110 	nscd_acc_data_t		*data)
111 {
112 	nscd_nsw_state_base_t	*base = (nscd_nsw_state_base_t *)data;
113 	nscd_nsw_state_t	*s, *ts;
114 	int			i;
115 	char			*me = "_nscd_free_nsw_state_base";
116 
117 	_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
118 	(me, "freeing db state base %p\n", base);
119 
120 	if (base == NULL)
121 		return;
122 
123 	for (i = 0; i < 2; i++) {
124 		if (i == 1)
125 			s = base->nsw_state.first;
126 		else
127 			s = base->nsw_state_thr.first;
128 
129 		while (s != NULL) {
130 			ts = s->next;
131 			_nscd_free_nsw_state(s);
132 			s = ts;
133 		}
134 	}
135 
136 	_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
137 	(me, "nsw state base %p freed \n", base);
138 }
139 
140 void
141 _nscd_free_all_nsw_state_base()
142 {
143 	nscd_nsw_state_base_t	*base;
144 	int			i;
145 	char			*me = "_nscd_free_all_nsw_state_base";
146 
147 	_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
148 	(me, "freeing all db state base\n");
149 
150 	(void) rw_wrlock(&nscd_nsw_state_base_lock);
151 	for (i = 0; i < NSCD_NUM_DB; i++) {
152 
153 		base = nscd_nsw_state_base[i];
154 		_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
155 		    NSCD_LOG_LEVEL_DEBUG)
156 		(me, "freeing db state base (%d) %p \n", i, base);
157 
158 		if (base == NULL)
159 			continue;
160 
161 		nscd_nsw_state_base[i] = (nscd_nsw_state_base_t *)
162 		    _nscd_set((nscd_acc_data_t *)base, NULL);
163 	}
164 	(void) rw_unlock(&nscd_nsw_state_base_lock);
165 }
166 
167 static nscd_nsw_state_t *
168 _nscd_create_nsw_state(
169 	nscd_nsw_params_t	*params)
170 {
171 	nscd_nsw_state_t	*s;
172 	nscd_nsw_config_t	*nsw_cfg;
173 	nscd_db_t		**be_db_p, *be_db;
174 	int			i, nobe = 1;
175 	char			*me = "_nscd_create_nsw_state";
176 
177 
178 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
179 	(me, "creating nsw state...\n");
180 
181 	s = calloc(1, sizeof (nscd_nsw_state_t));
182 	if (s == NULL) {
183 		if ((*s->nsw_cfg_p)->nobase  != 1)
184 			_nscd_release((nscd_acc_data_t *)params->nswcfg);
185 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
186 		(me, "not able to allocate a nsw state\n");
187 		return (NULL);
188 	} else
189 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
190 		(me, "nsw state %p allocated\n", s);
191 
192 	s->dbi = params->dbi;
193 	s->next = NULL;
194 
195 	nsw_cfg = *params->nswcfg;
196 
197 	s->nsw_cfg_p = params->nswcfg;
198 	s->config = nsw_cfg->nsw_config;
199 	s->max_src = nsw_cfg->max_src;
200 	s->p = params->p;
201 
202 	s->be = calloc(s->max_src, sizeof (nss_backend_t **));
203 	if (s->be == NULL) {
204 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
205 		(me, "not able to allocate s->be\n");
206 
207 		_nscd_free_nsw_state(s);
208 		return (NULL);
209 	} else {
210 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
211 		(me, "db be array %p allocated\n", s->be);
212 	}
213 
214 	s->be_constr = (nss_backend_constr_t *)calloc(s->max_src,
215 	    sizeof (nss_backend_constr_t));
216 	if (s->be_constr == NULL) {
217 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
218 		(me, "not able to allocate s->be_constr\n");
219 
220 		_nscd_free_nsw_state(s);
221 		return (NULL);
222 	} else {
223 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
224 		(me, "db be constructor array %p allocated\n", s->be_constr);
225 	}
226 
227 	s->be_version_p = (void **)calloc(s->max_src, sizeof (void *));
228 	if (s->be_version_p == NULL) {
229 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
230 		(me, "not able to allocate s->be_version_p\n");
231 
232 		_nscd_free_nsw_state(s);
233 		return (NULL);
234 	} else {
235 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
236 		(me, "db be version ptr array %p allocated\n", s->be_version_p);
237 	}
238 
239 	s->be_db_pp = calloc(s->max_src, sizeof (nscd_db_t ***));
240 	if (s->be_db_pp == NULL) {
241 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
242 		(me, "not able to allocate s->be_db_pp\n");
243 		_nscd_free_nsw_state(s);
244 		return (NULL);
245 	} else {
246 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
247 		(me, "be_db_pp array %p allocated\n", s->be_db_pp);
248 	}
249 
250 	/* create the source:database backends */
251 	for (i = 0;  i < s->max_src;  i++) {
252 		nss_backend_t		*be;
253 		int			srci;
254 		char			*srcn;
255 		const char		*dbn;
256 		struct __nsw_lookup_v1	*lkp;
257 		const nscd_db_entry_t	*dbe;
258 		nscd_be_info_t		*be_info;
259 
260 		if (i == 0)
261 			lkp = s->config->lookups;
262 		else
263 			lkp = lkp->next;
264 		if (lkp == NULL) {
265 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
266 			(me, "error: lkp is NULL\n");
267 			_nscd_free_nsw_state(s);
268 			return (NULL);
269 		}
270 
271 		srci = nsw_cfg->src_idx[i];
272 		srcn = lkp->service_name;
273 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
274 		(me, "source name = %s, index = %d\n", srcn, srci);
275 
276 		be_db_p = (nscd_db_t **)_nscd_get(
277 		    (nscd_acc_data_t *)nscd_src_backend_db[srci]);
278 		if (be_db_p == NULL) {
279 			_nscd_free_nsw_state(s);
280 			return (NULL);
281 		}
282 		be_db = *be_db_p;
283 		s->be_db_pp[i] = be_db_p;
284 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
285 		(me, "be db ptr array %p referenced\n", be_db_p);
286 
287 		be_info = NULL;
288 		be = NULL;
289 		dbn = params->p.name;
290 		dbe = _nscd_get_db_entry(be_db, NSCD_DATA_BACKEND_INFO,
291 		    (const char *)dbn, NSCD_GET_FIRST_DB_ENTRY, 0);
292 		if (dbe != NULL)
293 			be_info = (nscd_be_info_t *)*(dbe->data_array);
294 
295 		if (be_info == NULL || be_info->be_constr == NULL) {
296 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
297 			(me, "no backend info or be_constr is NULL "
298 			    "for <%s : %s>\n", NSCD_NSW_SRC_NAME(srci),
299 			    dbn);
300 		} else {
301 			s->be_constr[i] = be_info->be_constr;
302 			be = (be_info->be_constr)(dbn,
303 			    NSCD_NSW_SRC_NAME(srci), 0);
304 			if (be == NULL)
305 				s->recheck_be = nscd_true;
306 		}
307 
308 		if (be == NULL) {
309 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
310 			(me, "not able to init be for <%s : %s>\n",
311 			    NSCD_NSW_SRC_NAME(srci), dbn);
312 
313 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
314 			(me, "releasing db be ptr %p\n", be_db_p);
315 
316 			_nscd_release((nscd_acc_data_t *)be_db_p);
317 			s->be_db_pp[i] = NULL;
318 
319 			continue;
320 		}
321 
322 		s->be[i] = be;
323 		s->be_version_p[i] = be_info->be_version;
324 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
325 		(me, "backend version is %p\n", be_info->be_version);
326 		nobe = 0;
327 	}
328 
329 	if (nobe == 1) {
330 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
331 		(me, "NO backend found, returning NULL\n");
332 
333 		_nscd_free_nsw_state(s);
334 		return (NULL);
335 	}
336 
337 	return (s);
338 }
339 
340 /*
341  * Try to initialize the backend instances one more time
342  * in case the dependencies the backend libraries depend
343  * on are now available
344  */
345 static void
346 check_be_array(
347 	nscd_nsw_state_t	*s)
348 {
349 	int			i;
350 	char			*dbn;
351 	char			*srcn;
352 	struct __nsw_lookup_v1	*lkp;
353 
354 	dbn = NSCD_NSW_DB_NAME(s->dbi);
355 
356 	s->recheck_be = nscd_false;
357 	for (i = 0;  i < s->max_src;  i++) {
358 
359 		if (i == 0)
360 			lkp = s->config->lookups;
361 		else
362 			lkp = lkp->next;
363 		if (lkp == NULL)
364 			return;
365 
366 		srcn = lkp->service_name;
367 
368 		/*
369 		 * it is possible that 's->be[i]' could not be
370 		 * initialized earlier due to a dependency not
371 		 * yet available (e.g., nis on domain name),
372 		 * try to initialize one more time
373 		 */
374 		if (s->be[i] == NULL && s->be_constr[i] != NULL) {
375 			s->be[i] = (s->be_constr[i])(dbn, srcn, 0);
376 			if (s->be[i] == NULL)
377 				s->recheck_be = nscd_true;
378 		}
379 	}
380 }
381 
382 static nscd_rc_t
383 _get_nsw_state_int(
384 	nss_db_root_t		*rootp,
385 	nscd_nsw_params_t	*params,
386 	thread_t		*tid)
387 {
388 
389 	nscd_nsw_state_t	*ret = NULL;
390 	nscd_nsw_config_t	**nswcfg;
391 	nscd_nsw_state_base_t	*base;
392 	nscd_state_ctrl_t	*ctrl_p;
393 	int			thread_only = 0, wait_cond = 0;
394 	char			*me = "_get_nsw_state_int";
395 	int			dbi;
396 	nscd_rc_t		rc;
397 
398 	dbi = params->dbi;
399 
400 	/*
401 	 * no nsw state will be reused, if asked to use
402 	 * default config. So create the new structures
403 	 * used by the switch engine and the new nsw state
404 	 */
405 	if (params->p.flags & NSS_USE_DEFAULT_CONFIG) {
406 		rc = _nscd_create_sw_struct(dbi, -1, (char *)params->p.name,
407 		    (char *)params->p.default_config, NULL, params);
408 		if (rc != NSCD_SUCCESS)
409 			return (rc);
410 
411 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
412 		(me, "no base nsw config created for %s (sources: %s)\n",
413 		    params->p.name, params->p.default_config);
414 
415 		ret = _nscd_create_nsw_state(params);
416 		if (ret == NULL)
417 			return (NSCD_CREATE_NSW_STATE_FAILED);
418 		rootp->s = (struct nss_db_state *)ret;
419 		return (NSCD_SUCCESS);
420 	}
421 
422 	/*
423 	 * if getting a nsw state for a request from the compat
424 	 * backend, create the new switch structures if this
425 	 * is the first time around for a passwd, shadow, group,
426 	 * audit_user, or user_attr database
427 	 */
428 	if (params->compati != -1) {
429 
430 		nscd_nsw_config_t	**nswcfg1, **nswcfg2;
431 		int			i = params->compati;
432 
433 		dbi = i;
434 
435 		/*
436 		 * retrieve the pointer space which contains a
437 		 * pointer pointing to the nsswitch config
438 		 * structure for the compat backend
439 		 */
440 		nswcfg = (nscd_nsw_config_t **)_nscd_get(
441 		    (nscd_acc_data_t *)nscd_nsw_config[i]);
442 
443 		/*
444 		 * If nsswitch config structure not created yet,
445 		 * get the config string from the passwd_compat
446 		 * or group_compat DB and create the structure.
447 		 */
448 		if (*nswcfg == NULL) {
449 			/* Wait first if it's being created. */
450 			nswcfg2 = (nscd_nsw_config_t **)_nscd_mutex_lock(
451 			    (nscd_acc_data_t *)nscd_nsw_config[i]);
452 
453 			/* still not created yet */
454 			if (*nswcfg2 == NULL) {
455 				/*
456 				 * get the nsswitch config string specified
457 				 * for passwd_compat or group_compat
458 				 */
459 				nswcfg1 = (nscd_nsw_config_t **)_nscd_get(
460 				    (nscd_acc_data_t *)
461 				    nscd_nsw_config[params->cfgdbi]);
462 				if (nswcfg1 == NULL) {
463 					_NSCD_LOG(NSCD_LOG_NSW_STATE,
464 					    NSCD_LOG_LEVEL_ERROR)
465 					(me, "no nsw config for %s\n",
466 					    params->p.name);
467 
468 					(void) _nscd_mutex_unlock(
469 					    (nscd_acc_data_t *)nswcfg2);
470 					_nscd_release((nscd_acc_data_t *)
471 					    nswcfg);
472 
473 					return (NSCD_CREATE_NSW_STATE_FAILED);
474 				}
475 
476 				rc = _nscd_create_sw_struct(i, params->cfgdbi,
477 				    params->p.name, (*nswcfg1)->nsw_cfg_str,
478 				    NULL, params);
479 				_nscd_release((nscd_acc_data_t *)nswcfg1);
480 
481 				if (rc == NSCD_SUCCESS) {
482 					_NSCD_LOG(NSCD_LOG_NSW_STATE,
483 					    NSCD_LOG_LEVEL_DEBUG)
484 					(me, "nsw config created for %s (%s)\n",
485 					    params->p.name,
486 					    (*nswcfg1)->nsw_cfg_str);
487 				} else {
488 					(void) _nscd_mutex_unlock(
489 					    (nscd_acc_data_t *)nswcfg2);
490 					_nscd_release((nscd_acc_data_t *)
491 					    nswcfg);
492 					return (rc);
493 				}
494 			}
495 			(void) _nscd_mutex_unlock((nscd_acc_data_t *)nswcfg2);
496 		}
497 		_nscd_release((nscd_acc_data_t *)nswcfg);
498 	}
499 
500 	(void) rw_rdlock(&nscd_nsw_state_base_lock);
501 	base = nscd_nsw_state_base[dbi];
502 	(void) rw_unlock(&nscd_nsw_state_base_lock);
503 	if (base == NULL)
504 		assert(base != NULL);
505 
506 	/*
507 	 * If list is not empty, return the first one on list.
508 	 * Otherwise, create and return a new db state if the
509 	 * limit is not reached. if reacehed, wait for the 'one
510 	 * is available' signal.
511 	 */
512 	assert(base == (nscd_nsw_state_base_t *)_nscd_mutex_lock(
513 	    (nscd_acc_data_t *)base));
514 
515 	if (tid == NULL) {
516 		ctrl_p = &base->nsw_state;
517 	} else {
518 		thread_only = 1;
519 		ctrl_p = &base->nsw_state_thr;
520 
521 		_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
522 			_nscd_logit(me, "per thread nsw state info: \n");
523 			_nscd_logit(me, "tid = %d\n", *tid);
524 			_nscd_logit(me, "tid in base = %d\n", base->tid);
525 			_nscd_logit(me, "number of free nsw_state = %d\n",
526 			    ctrl_p->free);
527 			_nscd_logit(me, "number of nsw state allocated = %d\n",
528 			    ctrl_p->allocated);
529 			_nscd_logit(me, "first nsw state on list = %p\n",
530 			    ctrl_p->first);
531 			_nscd_logit(me, "number of waiter = %d\n",
532 			    ctrl_p->waiter);
533 
534 		}
535 	}
536 
537 	if (ctrl_p->first == NULL && ctrl_p->allocated == ctrl_p->max)
538 		wait_cond = 1;
539 	else if (thread_only && base->used_by_thr && base->tid != *tid)
540 		wait_cond = 1;
541 
542 	if (wait_cond) {
543 
544 		ctrl_p->waiter++;
545 
546 		while (wait_cond) {
547 			if (!thread_only)
548 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
549 				    NSCD_LOG_LEVEL_DEBUG)
550 				(me, "waiting for nsw state signal\n");
551 			else
552 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
553 				    NSCD_LOG_LEVEL_DEBUG)
554 				(me, "waiting for per thread "
555 				    "nsw state signal\n");
556 
557 			if (thread_only) {
558 				_nscd_cond_wait((nscd_acc_data_t *)base,
559 				    &base->thr_cond);
560 
561 				if (base->used_by_thr == 0 &&
562 				    ctrl_p->first != NULL)
563 					wait_cond = 0;
564 			} else {
565 				_nscd_cond_wait((nscd_acc_data_t *)base, NULL);
566 
567 				if (ctrl_p->first != NULL)
568 					wait_cond = 0;
569 			}
570 
571 			if (!thread_only)
572 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
573 				    NSCD_LOG_LEVEL_DEBUG)
574 				(me, "woke from cond wait ...wait_cond = %d\n",
575 				    wait_cond);
576 			else
577 
578 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
579 				    NSCD_LOG_LEVEL_DEBUG)
580 				(me, "woke from cond wait (per thread) "
581 				    "...wait_cond = %d\n", wait_cond);
582 
583 		}
584 
585 		ctrl_p->waiter--;
586 	}
587 
588 	if (ctrl_p->first == NULL) {
589 		int	geti;
590 
591 		/*
592 		 * for lookup calls from the compat backend
593 		 * uses the switch policy for passwd_compat
594 		 * or group_compat
595 		 */
596 		if (params->compati != -1)
597 			geti = params->compati;
598 		else
599 			geti = params->dbi;
600 
601 		params->nswcfg = (nscd_nsw_config_t **)_nscd_get(
602 		    (nscd_acc_data_t *)nscd_nsw_config[geti]);
603 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
604 		(me, "got a nsw config %p for index %d\n",
605 		    params->nswcfg, geti);
606 
607 		ctrl_p->first = _nscd_create_nsw_state(params);
608 		if (ctrl_p->first != NULL) {
609 			if (tid == NULL) {
610 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
611 				    NSCD_LOG_LEVEL_DEBUG)
612 				(me, "got a new nsw_state %p\n", ctrl_p->first);
613 			} else {
614 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
615 				    NSCD_LOG_LEVEL_DEBUG)
616 				(me, "got a new per thread nsw_state %p\n",
617 				    ctrl_p->first);
618 			}
619 			ctrl_p->allocated++;
620 			ctrl_p->free++;
621 		} else {
622 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
623 				(me, "error: unable to obtain a nsw state\n");
624 			_nscd_mutex_unlock((nscd_acc_data_t *)base);
625 			return (NSCD_CREATE_NSW_STATE_FAILED);
626 		}
627 	}
628 
629 	ret = ctrl_p->first;
630 	if (ret->recheck_be == nscd_true)
631 		check_be_array(ret);
632 	ctrl_p->first = ret->next;
633 	ret->next = NULL;
634 	ctrl_p->free--;
635 	if (thread_only) {
636 		base->tid = *tid;
637 		base->used_by_thr = 1;
638 
639 		_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
640 			_nscd_logit(me, "\t\t\tgot a per thread nsw "
641 			    "state %p: \n", ret);
642 			_nscd_logit(me, "tid = %d\n", *tid);
643 			_nscd_logit(me, "tid in base = %d\n", base->tid);
644 			_nscd_logit(me, "number of free nsw_state = %d\n",
645 			    ctrl_p->free);
646 			_nscd_logit(me, "number od nsw state allocated = %d\n",
647 			    ctrl_p->allocated);
648 			_nscd_logit(me, "first nsw state on list = %p\n",
649 			    ctrl_p->first);
650 			_nscd_logit(me, "number of waiter = %d\n",
651 			    ctrl_p->waiter);
652 		}
653 	}
654 	else
655 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
656 		(me, "got old nsw state %p\n", ret);
657 
658 	/*
659 	 * reference count the nsswitch state base bfore handing out
660 	 * the nsswitch state
661 	 */
662 	ret->base = (nscd_nsw_state_base_t *)
663 	    _nscd_get((nscd_acc_data_t *)base);
664 
665 	_nscd_mutex_unlock((nscd_acc_data_t *)base);
666 
667 	rootp->s = (struct nss_db_state *)ret;
668 
669 	return (NSCD_SUCCESS);
670 }
671 
672 nscd_rc_t
673 _nscd_get_nsw_state(
674 	nss_db_root_t		*rootp,
675 	nscd_nsw_params_t	*params)
676 {
677 	return (_get_nsw_state_int(rootp, params, NULL));
678 }
679 
680 nscd_rc_t
681 _nscd_get_nsw_state_thread(
682 	nss_db_root_t		*rootp,
683 	nscd_nsw_params_t	*params)
684 {
685 	thread_t	tid = thr_self();
686 	return (_get_nsw_state_int(rootp, params, &tid));
687 }
688 
689 
690 static void
691 _put_nsw_state_int(
692 	nscd_nsw_state_t	*s,
693 	thread_t		*tid)
694 {
695 
696 	nscd_nsw_state_base_t	*base;
697 	nscd_state_ctrl_t	*ctrl_p;
698 	int			thread_only = 0;
699 	char			*me = "_put_nsw_state_int";
700 
701 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
702 	(me, "put back a nsw state\n");
703 
704 	if (s == NULL) {
705 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
706 		(me, "nsw state is NULL, nothing to put back\n");
707 		return;
708 	}
709 
710 	/*
711 	 * no need to put back if the nsw state is not on any base
712 	 * but need to free the resources used
713 	 */
714 	if ((*s->nsw_cfg_p)->nobase  == 1) {
715 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
716 		(me, "no base nsw state, freeing resources ...\n");
717 
718 		_nscd_free_nsw_state(s);
719 		return;
720 	}
721 
722 	if (tid != NULL)
723 		thread_only = 1;
724 
725 	base = s->base;
726 
727 	if (_nscd_mutex_lock((nscd_acc_data_t *)base) == NULL) {
728 		/* base has been freed or no longer valid, free the nsw state */
729 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
730 		(me, "nsw state base gone or no longer valid, freeing %p\n", s);
731 		_nscd_free_nsw_state(s);
732 		return;
733 	}
734 
735 	if (thread_only)
736 		ctrl_p = &base->nsw_state_thr;
737 	else
738 		ctrl_p = &base->nsw_state;
739 
740 	_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
741 		_nscd_logit(me, "before returning the nsw state: \n");
742 		_nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid);
743 		_nscd_logit(me, "tid in base = %d\n", base->tid);
744 		_nscd_logit(me, "number of free nsw_state = %d\n",
745 		    ctrl_p->free);
746 		_nscd_logit(me, "number od nsw state allocated = %d\n",
747 		    ctrl_p->allocated);
748 		_nscd_logit(me, "first nsw state on list = %p\n",
749 		    ctrl_p->first);
750 		_nscd_logit(me, "number of waiter = %d\n", ctrl_p->waiter);
751 	}
752 
753 	if (ctrl_p->first != NULL) {
754 		s->next = ctrl_p->first;
755 		ctrl_p->first = s;
756 	} else {
757 		ctrl_p->first = s;
758 		s->next = NULL;
759 	}
760 	ctrl_p->free++;
761 
762 	/*
763 	 * Remove reference to the nsswitch state base.
764 	 */
765 	_nscd_release((nscd_acc_data_t *)base);
766 	s->base = NULL;
767 
768 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
769 	(me, "signaling waiter thread_only = %d..\n", thread_only);
770 
771 	if (thread_only && ctrl_p->free == ctrl_p->allocated) {
772 		assert(ctrl_p->first != NULL);
773 		base->used_by_thr = 0;
774 		if (ctrl_p->waiter > 0) {
775 			(void) cond_signal(&base->thr_cond);
776 		}
777 	}
778 
779 	if (!thread_only && ctrl_p->waiter > 0) {
780 
781 		_nscd_cond_signal((nscd_acc_data_t *)base);
782 	}
783 
784 	_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
785 		_nscd_logit(me, "after the nsw state is returned: \n");
786 		_nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid);
787 		_nscd_logit(me, "tid in base = %d\n", base->tid);
788 		_nscd_logit(me, "number of free nsw_state = %d\n",
789 		    ctrl_p->free);
790 		_nscd_logit(me, "number od nsw state allocated = %d\n",
791 		    ctrl_p->allocated);
792 		_nscd_logit(me, "first nsw state on list = %p\n",
793 		    ctrl_p->first);
794 		_nscd_logit(me, "tnumber of waiter = %d\n", ctrl_p->waiter);
795 	}
796 
797 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
798 	(me, "done putting back nsw state %p, thread_only = %d\n",
799 	    s, thread_only);
800 
801 	_nscd_mutex_unlock((nscd_acc_data_t *)base);
802 
803 }
804 
805 void
806 _nscd_put_nsw_state(
807 	nscd_nsw_state_t	*s)
808 {
809 	_put_nsw_state_int(s, NULL);
810 }
811 
812 void
813 _nscd_put_nsw_state_thread(
814 	nscd_nsw_state_t	*s)
815 {
816 	thread_t		tid = thr_self();
817 	_put_nsw_state_int(s, &tid);
818 }
819 
820 nscd_rc_t
821 _nscd_init_nsw_state_base(
822 	int			dbi,
823 	int			compat_basei,
824 	int			lock)
825 {
826 	int			cfgdbi;
827 	nscd_nsw_state_base_t	*base = NULL;
828 	char			*me = "_nscd_init_nsw_state_base";
829 
830 	if (lock)
831 		(void) rw_rdlock(&nscd_nsw_state_base_lock);
832 
833 	base = (nscd_nsw_state_base_t *)_nscd_alloc(
834 	    NSCD_DATA_NSW_STATE_BASE,
835 	    sizeof (nscd_nsw_state_base_t),
836 	    _nscd_free_nsw_state_base,
837 	    NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND);
838 
839 	if (base == NULL) {
840 		_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
841 		    NSCD_LOG_LEVEL_ERROR)
842 		(me, "not able to allocate a nsw state base\n");
843 		if (lock)
844 			(void) rw_unlock(&nscd_nsw_state_base_lock);
845 		return (NSCD_NO_MEMORY);
846 	}
847 	_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
848 		(me, "nsw state base %p allocated\n", base);
849 
850 	/*
851 	 * initialize and activate the new nss_nsw_state base
852 	 */
853 	base->dbi = dbi;
854 	if (compat_basei != -1)
855 		cfgdbi = compat_basei;
856 	else
857 		cfgdbi = dbi;
858 
859 	base->nsw_state.max = NSCD_SW_CFG(cfgdbi).max_nsw_state_per_db;
860 	base->nsw_state_thr.max = NSCD_SW_CFG(cfgdbi).max_nsw_state_per_thread;
861 
862 	nscd_nsw_state_base[dbi] = (nscd_nsw_state_base_t *)_nscd_set(
863 	    (nscd_acc_data_t *)nscd_nsw_state_base[dbi],
864 	    (nscd_acc_data_t *)base);
865 
866 	if (lock)
867 		(void) rw_unlock(&nscd_nsw_state_base_lock);
868 
869 	return (NSCD_SUCCESS);
870 }
871 
872 nscd_rc_t
873 _nscd_init_all_nsw_state_base()
874 {
875 	int			i;
876 	nscd_rc_t		rc;
877 	char			*me = "_nscd_init_all_nsw_state_base";
878 
879 	(void) rw_rdlock(&nscd_nsw_state_base_lock);
880 
881 	for (i = 0; i < NSCD_NUM_DB; i++) {
882 
883 		rc = _nscd_init_nsw_state_base(i, -1, 0);
884 
885 		if (rc != NSCD_SUCCESS) {
886 			_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
887 			    NSCD_LOG_LEVEL_ERROR)
888 			(me, "not able to initialize a nsw db state "
889 			    "base (%d)\n", i);
890 
891 			(void) rw_unlock(&nscd_nsw_state_base_lock);
892 			return (rc);
893 		}
894 	}
895 	_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
896 	(me, "all nsw state base initialized\n");
897 
898 	(void) rw_unlock(&nscd_nsw_state_base_lock);
899 
900 	return (NSCD_SUCCESS);
901 }
902 
903 nscd_rc_t
904 _nscd_alloc_nsw_state_base()
905 {
906 
907 	(void) rw_rdlock(&nscd_nsw_state_base_lock);
908 
909 	nscd_nsw_state_base = calloc(NSCD_NUM_DB,
910 	    sizeof (nscd_nsw_state_base_t *));
911 	if (nscd_nsw_state_base == NULL) {
912 		(void) rw_unlock(&nscd_nsw_state_base_lock);
913 		return (NSCD_NO_MEMORY);
914 	}
915 
916 	(void) rw_rdlock(&nscd_nsw_state_base_lock);
917 
918 	return (NSCD_SUCCESS);
919 }
920