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