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