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