xref: /illumos-gate/usr/src/cmd/nscd/nscd_nswconfig.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 <nss_common.h>
29 #include <dlfcn.h>
30 #include <alloca.h>
31 
32 #include <stdlib.h>
33 #include <libscf_priv.h>
34 #include <string.h>
35 #include <assert.h>
36 #include "nscd_switch.h"
37 #include "nscd_log.h"
38 #include "nscd_db.h"
39 
40 /*
41  * _nscd_nss_finders is used to replace the nss_default_finders in libc
42  * to allow nscd to have more control over the dl handles when using
43  * dlsym to get the address of the nss backend instance constructors
44  */
45 static nss_backend_constr_t _nscd_per_src_lookup(void *,
46 	const char *, const char *, void **);
47 static void _nscd_per_src_delete(void *, nss_backend_constr_t);
48 
49 static nss_backend_finder_t _nscd_per_src = {
50 	_nscd_per_src_lookup,
51 	_nscd_per_src_delete,
52 	0,
53 	0 };
54 
55 nss_backend_finder_t *_nscd_nss_finders = &_nscd_per_src;
56 
57 /*
58  * nscd database for each source. It contains backend
59  * info (nscd_be_info_t) for each naming database.
60  * Protected by nscd_src_backend_db_lock.
61  */
62 nscd_db_t	***nscd_src_backend_db;
63 int		*nscd_src_backend_db_loaded;
64 static		rwlock_t nscd_src_backend_db_lock = DEFAULTRWLOCK;
65 
66 /*
67  * nsswitch config monitored by nscd. Protected by
68  * readers/writer lock nscd_nsw_config_lock
69  */
70 nscd_nsw_config_t ***nscd_nsw_config;
71 static rwlock_t nscd_nsw_config_lock = DEFAULTRWLOCK;
72 
73 /*
74  * nsswitch source index/name array
75  * (allow 32 foreign nsswitch sources/backends)
76  */
77 #define		NSCD_NUM_SRC_FOREIGN 32
78 nscd_cfg_id_t	*_nscd_cfg_nsw_src_all;
79 int		_nscd_cfg_num_nsw_src_all;
80 
81 static void
82 free_nscd_nsw_config(
83 	nscd_acc_data_t		*data)
84 {
85 
86 	nscd_nsw_config_t	*nsw_cfg = *(nscd_nsw_config_t **)data;
87 	char			*me = "free_nscd_nsw_config";
88 
89 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
90 	(me, "freeing nscd nsw config %p \n", nsw_cfg);
91 	if (nsw_cfg == NULL)
92 		return;
93 
94 	if (nsw_cfg->db_name != NULL)
95 		free(nsw_cfg->db_name);
96 	if (nsw_cfg->nsw_cfg_str != NULL)
97 		free(nsw_cfg->nsw_cfg_str);
98 	if (nsw_cfg->nsw_config != NULL)
99 		(void) __nsw_freeconfig_v1(nsw_cfg->nsw_config);
100 	if (nsw_cfg->src_idx != NULL)
101 		free(nsw_cfg->src_idx);
102 
103 	free(nsw_cfg);
104 }
105 
106 
107 void
108 _nscd_free_nsw_config(
109 	nscd_nsw_config_t *nswcfg)
110 {
111 	free_nscd_nsw_config((nscd_acc_data_t *)&nswcfg);
112 }
113 
114 void
115 _nscd_free_all_nsw_config()
116 {
117 
118 	nscd_nsw_config_t	**nsw_cfg;
119 	int			i;
120 	char			*me = "_nscd_free_all_nsw_config";
121 
122 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
123 	(me, "freeing all nscd nsw config \n");
124 
125 	(void) rw_wrlock(&nscd_nsw_config_lock);
126 	for (i = 0; i < NSCD_NUM_DB; i++) {
127 
128 		if ((nsw_cfg = nscd_nsw_config[i]) == NULL)
129 			continue;
130 
131 		nscd_nsw_config[i] = (nscd_nsw_config_t **)_nscd_set(
132 		    (nscd_acc_data_t *)nsw_cfg, NULL);
133 	}
134 	(void) rw_unlock(&nscd_nsw_config_lock);
135 }
136 
137 
138 static void
139 free_nsw_backend_info_db(nscd_acc_data_t *data)
140 {
141 
142 	nscd_db_t	*db = *(nscd_db_t **)data;
143 	char		*me = "free_nsw_backend_info_db";
144 
145 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
146 	(me, "freeing nsw backend info db %p\n", db);
147 
148 	if (db == NULL)
149 		return;
150 
151 	_nscd_free_db(db);
152 
153 }
154 
155 void
156 _nscd_free_all_nsw_backend_info_db()
157 {
158 
159 	nscd_db_t	**db;
160 	int		i;
161 	char		*me = " _nscd_free_all_nsw_backend_info_db";
162 
163 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
164 	(me, "freeing all nsw backend info db\n");
165 
166 	(void) rw_wrlock(&nscd_src_backend_db_lock);
167 	for (i = 0; i < NSCD_NUM_SRC; i++) {
168 
169 		if ((db = nscd_src_backend_db[i]) == NULL)
170 			continue;
171 
172 		nscd_src_backend_db[i] = (nscd_db_t **)_nscd_set(
173 		    (nscd_acc_data_t *)db, NULL);
174 		nscd_src_backend_db_loaded[i] = 0;
175 	}
176 	(void) rw_unlock(&nscd_src_backend_db_lock);
177 }
178 
179 /*
180  * Populate the backend info db for the 'NSCD_NSW_SRC_NAME(srci)'
181  * source.  Create one entry for each source/database pair
182  * (e.g., ldap:passwd, nis:hosts, etc).
183  */
184 static nscd_rc_t
185 _nscd_populate_nsw_backend_info_db(int srci)
186 {
187 	nscd_be_info_t		be_info, *bi;
188 	nss_backend_finder_t	*bf;
189 	nscd_nsw_config_t	*nsw_cfg;
190 	int			i, size;
191 	nscd_db_entry_t		*db_entry;
192 	char			*src = NSCD_NSW_SRC_NAME(srci);
193 	const char		*dbn;
194 	char			*me = "_nscd_populate_nsw_backend_info_db";
195 	void			*handle = NULL;
196 	nss_backend_constr_t	c;
197 	void			*be_version = &_nscd_be_version;
198 
199 	/* get the version number of the backend (if available) */
200 	if (srci >= _nscd_cfg_num_nsw_src) { /* a foreign backend */
201 		c = _nscd_per_src_lookup(handle, NULL, src, &handle);
202 		if (c == NULL)
203 			be_version = NULL;
204 		else
205 			be_version = (void *)c;
206 
207 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
208 		(me, "foreign backend: _nss_%s_version = %p ", src, be_version);
209 	}
210 
211 	for (i = 0; i < NSCD_NUM_DB; i++) {
212 
213 		if (nscd_nsw_config[i] == NULL)
214 			continue;
215 
216 		nsw_cfg = *nscd_nsw_config[i];
217 		dbn = NSCD_NSW_DB_NAME(i);
218 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
219 		(me, "adding backend info for <%s : %s>\n", src, dbn);
220 
221 		(void) memset(&be_info, 0, sizeof (be_info));
222 
223 		for (bf = nsw_cfg->fe_params.finders;  bf != 0; bf = bf->next) {
224 
225 			c = (*bf->lookup)(handle, dbn, src, &handle);
226 
227 			if (c != 0) {
228 				be_info.be_constr = c;
229 				be_info.finder = bf;
230 				be_info.finder_priv = handle;
231 				be_info.be_version = be_version;
232 				break;
233 			}
234 		}
235 		if (be_info.be_constr == NULL) {
236 			/*
237 			 * Couldn't find the backend anywhere.
238 			 * This is fine, some backend just don't
239 			 * support certain databases.
240 			 */
241 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
242 			(me, "unable to find backend info "
243 			    "for <%s : %s>\n", src, dbn);
244 		}
245 
246 		size = sizeof (nscd_be_info_t);
247 
248 		db_entry = _nscd_alloc_db_entry(NSCD_DATA_BACKEND_INFO,
249 		    dbn, size, 1, 1);
250 
251 		if (db_entry == NULL) {
252 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
253 			(me, "unable to allocate db entry for "
254 			    "<%s : %s>\n", src, dbn);
255 			return (NSCD_NO_MEMORY);
256 		}
257 
258 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
259 		(me, "adding be db entry %p for <%s : %s> to db %p: "
260 		    "constr = %p\n", db_entry, src, dbn,
261 		    *nscd_src_backend_db[srci], be_info.be_constr);
262 
263 		bi = (nscd_be_info_t *)*(db_entry->data_array);
264 		*bi = be_info;
265 
266 		(void) _nscd_wrlock((nscd_acc_data_t *)
267 		    nscd_src_backend_db[srci]);
268 		nscd_src_backend_db_loaded[srci] = 1;
269 		(void) _nscd_add_db_entry(*nscd_src_backend_db[srci],
270 		    dbn, db_entry, NSCD_ADD_DB_ENTRY_LAST);
271 		(void) _nscd_rw_unlock((nscd_acc_data_t *)
272 		    nscd_src_backend_db[srci]);
273 	}
274 
275 	return (NSCD_SUCCESS);
276 }
277 
278 /*
279  * create data structures (used by the switch engine) based
280  * on the input switch policy configuration and database
281  * name and indexes
282  */
283 nscd_rc_t
284 _nscd_create_sw_struct(
285 	int				dbi,
286 	int				compat_basei,
287 	const char			*dbn,
288 	const char			*cfgstr,
289 	void				*swcfgv1,
290 	nscd_nsw_params_t		*params)
291 {
292 	char				*me = "_nscd_create_sw_struct";
293 	nscd_rc_t			rc = NSCD_SUCCESS;
294 	nscd_nsw_config_t		*nsw_cfg = NULL;
295 	nscd_nsw_config_t		**nsw_cfg_p = NULL;
296 	struct __nsw_switchconfig_v1	*swcfg = NULL;
297 	struct __nsw_lookup_v1		*lkp;
298 	enum __nsw_parse_err		err;
299 	int				maxsrc;
300 	int				*src_idx_a = NULL;
301 	int				j, k;
302 
303 	/*
304 	 * if the nsw config string has been parsed into
305 	 * a struct __nsw_switchconfig_v1, use it. If not,
306 	 * create the struct.
307 	 */
308 	if (swcfgv1 != NULL)
309 		swcfg = (struct __nsw_switchconfig_v1 *)swcfgv1;
310 	else {
311 		char	*cstr;
312 
313 		cstr = strdup(cfgstr);
314 		if (cstr == NULL)
315 			return (NSCD_NO_MEMORY);
316 
317 		/*
318 		 * parse the nsw config string and create
319 		 * a struct __nsw_switchconfig_v1
320 		 */
321 		swcfg = _nsw_getoneconfig_v1(dbn, cstr, &err);
322 		free(cstr);
323 		if (swcfg == NULL) {
324 			rc = NSCD_CFG_SYNTAX_ERROR;
325 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
326 			(me, "error: unable to process nsw config string\n");
327 			goto error_exit;
328 		}
329 	}
330 
331 	/* allocate the space for a nscd_nsw_config_t */
332 	nsw_cfg = calloc(1, sizeof (nscd_nsw_config_t));
333 	if (nsw_cfg == NULL) {
334 		rc = NSCD_NO_MEMORY;
335 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
336 		(me, "error: unable to allocate an nscd_nsw_config_t\n");
337 		goto error_exit;
338 	}
339 
340 	/* need to know how many backends (sources) */
341 	maxsrc = swcfg->num_lookups;
342 	nsw_cfg->max_src = maxsrc;
343 
344 	/*
345 	 * allocate an array to store the index for each
346 	 * backend (source)
347 	 */
348 	src_idx_a = calloc(1, maxsrc * sizeof (int));
349 	if (src_idx_a == NULL) {
350 		rc = NSCD_NO_MEMORY;
351 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
352 		(me, "error: unable to allocate an array for source index\n");
353 		goto error_exit;
354 	}
355 
356 	/*
357 	 * set the index for each backend (source)
358 	 */
359 	lkp = swcfg->lookups;
360 	for (j = 0; j < maxsrc; j++) {
361 		char *usrc;
362 
363 		for (k = 0; k < NSCD_NUM_SRC && NSCD_NSW_SRC_NAME(k) != NULL &&
364 		    strcmp(lkp->service_name, NSCD_NSW_SRC_NAME(k)) != 0;
365 		    k++) {
366 			/* empty */
367 		}
368 
369 		if (k < NSCD_NUM_SRC && nscd_src_backend_db_loaded[k] == 0) {
370 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
371 			(me, "unknown nsw source name %s\n", lkp->service_name);
372 			usrc = strdup(lkp->service_name);
373 			if (usrc == NULL) {
374 				rc = NSCD_NO_MEMORY;
375 				_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
376 				(me, "unable to strdup() source name\n");
377 				goto error_exit;
378 			}
379 			NSCD_NSW_SRC_NAME(k) = usrc;
380 
381 			rc = _nscd_populate_nsw_backend_info_db(k);
382 			if (rc != NSCD_SUCCESS) {
383 				free(usrc);
384 				NSCD_NSW_SRC_NAME(k) = NULL;
385 				goto error_exit;
386 			}
387 		} else if (NSCD_NSW_SRC_NAME(k) == NULL) {
388 			/*
389 			 * number of user-defined source exceeded
390 			 */
391 			rc = NSCD_CFG_SYNTAX_ERROR;
392 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
393 			(me, "error: number of user_defined source exceeded\n");
394 
395 			goto error_exit;
396 		}
397 
398 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
399 		(me, "setting source index array [%d] = %d (%s)\n",
400 		    j, k, lkp->service_name);
401 
402 		src_idx_a[j] = k;
403 
404 		lkp = lkp->next;
405 		if (lkp == NULL) break;
406 
407 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
408 		(me, "number of nsw sources = %d\n", nsw_cfg->max_src);
409 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
410 		(me, "next nsw source is %s\n", lkp->service_name);
411 	}
412 
413 	/* set it up to reference count the switch policy config */
414 	nsw_cfg_p = (nscd_nsw_config_t **)_nscd_alloc(NSCD_DATA_NSW_CONFIG,
415 	    sizeof (nscd_nsw_config_t **), free_nscd_nsw_config,
416 	    NSCD_ALLOC_RWLOCK);
417 
418 	if (nsw_cfg_p == NULL) {
419 		rc = NSCD_NO_MEMORY;
420 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
421 		(me, "unable to allocate a new nsw config DB\n");
422 		goto error_exit;
423 	}
424 	*nsw_cfg_p = nsw_cfg;
425 
426 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
427 	(me, "new nsw config DB %p allocated\n", nsw_cfg_p);
428 
429 	/* save all the data in the new nscd_nsw_config_t */
430 	nsw_cfg->db_name = strdup(dbn);
431 	nsw_cfg->nsw_cfg_str = strdup(cfgstr);
432 	if (nsw_cfg->db_name == NULL || nsw_cfg->nsw_cfg_str == NULL) {
433 		rc = NSCD_NO_MEMORY;
434 		goto error_exit;
435 	}
436 
437 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
438 	(me, "switch policy \"%s\" for database is \"%s\"\n",
439 	    nsw_cfg->db_name, nsw_cfg->nsw_cfg_str);
440 
441 	nsw_cfg->nsw_config = swcfg;
442 	nsw_cfg->src_idx = src_idx_a;
443 
444 	/*
445 	 * set default frontend params and if necessary call initf()
446 	 * to initialize or override
447 	 */
448 	nsw_cfg->fe_params.max_active_per_src = 10;
449 	nsw_cfg->fe_params.max_dormant_per_src = 1;
450 	nsw_cfg->fe_params.finders = _nscd_nss_finders;
451 	if (params != NULL) {
452 		nsw_cfg->fe_params = params->p;
453 
454 		if (params->p.flags & NSS_USE_DEFAULT_CONFIG) {
455 			params->nswcfg = nsw_cfg_p;
456 			/*
457 			 * this nsw_cfg is not meant to last long, no need
458 			 * to set up the nsw state and getent bases, just
459 			 * exit with NSCD_SUCCESS
460 			 */
461 			nsw_cfg->nobase = 1;
462 			goto error_exit;
463 		}
464 	} else
465 		(void) (nscd_nss_db_initf[dbi])(&nsw_cfg->fe_params);
466 
467 	/*
468 	 * activate the new nscd_nsw_config_t, the old one
469 	 * will either be deleted or left on the side (and be
470 	 * deleted eventually)
471 	 */
472 	nscd_nsw_config[dbi] = (nscd_nsw_config_t **)_nscd_set(
473 	    (nscd_acc_data_t *)nscd_nsw_config[dbi],
474 	    (nscd_acc_data_t *)nsw_cfg_p);
475 
476 	/*
477 	 * also create a new nsw state base
478 	 */
479 	if ((rc = _nscd_init_nsw_state_base(dbi, compat_basei, 1)) !=
480 	    NSCD_SUCCESS) {
481 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
482 		(me, "unable to initialize a nsw state base(%d)\n", dbi);
483 		goto error_exit;
484 	}
485 
486 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
487 	(me, "new nsw state base(%d) %p created\n", dbi,
488 	    nscd_nsw_state_base[dbi]);
489 
490 	/*
491 	 * also create a new getent context base
492 	 */
493 	if ((rc = _nscd_init_getent_ctx_base(dbi, 1)) != NSCD_SUCCESS) {
494 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
495 		(me, "unable to initialize a getent context base(%d)\n", dbi);
496 		goto error_exit;
497 	}
498 
499 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
500 	(me, "new getent context base(%d) %p created\n", dbi,
501 	    nscd_getent_ctx_base[dbi]);
502 
503 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
504 	(me, "new nsw config created (database = %s, "
505 	"config = %s)\n", dbn, cfgstr);
506 
507 
508 	error_exit:
509 
510 	if (rc != NSCD_SUCCESS) {
511 
512 		if (swcfgv1 == NULL && swcfg != NULL)
513 			(void) __nsw_freeconfig_v1(swcfg);
514 		if (src_idx_a != NULL)
515 			free(src_idx_a);
516 		if (nsw_cfg_p)
517 			free(nsw_cfg_p);
518 		if (nsw_cfg != NULL) {
519 			if (nsw_cfg->db_name != NULL)
520 				free(nsw_cfg->db_name);
521 			if (nsw_cfg->nsw_cfg_str != NULL)
522 				free(nsw_cfg->nsw_cfg_str);
523 			free(nsw_cfg);
524 		}
525 
526 		return (rc);
527 	} else
528 		return (NSCD_SUCCESS);
529 }
530 
531 static nscd_rc_t
532 create_nsw_config(int dbi)
533 {
534 
535 	nscd_nsw_config_t	*nsw_cfg = NULL;
536 	nscd_nsw_config_t	**nsw_cfg_p = NULL;
537 	char			*me = "create_nsw_config";
538 
539 	/*
540 	 * if pseudo-databases (initf function not defined),
541 	 * don't bother now
542 	 */
543 	if (nscd_nss_db_initf[dbi] == NULL)
544 		return (NSCD_SUCCESS);
545 
546 	/* allocate the space for a nscd_nsw_config_t */
547 	nsw_cfg = calloc(1, sizeof (nscd_nsw_config_t));
548 	if (nsw_cfg == NULL) {
549 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
550 		(me, "unable to allocate a nsw config structure\n");
551 		return (NSCD_NO_MEMORY);
552 	}
553 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
554 	(me, "nsw config structure %pallocated\n", nsw_cfg);
555 
556 	nsw_cfg_p = (nscd_nsw_config_t **)_nscd_alloc(NSCD_DATA_NSW_CONFIG,
557 	    sizeof (nscd_nsw_config_t **), free_nscd_nsw_config,
558 	    NSCD_ALLOC_RWLOCK);
559 
560 	if (nsw_cfg_p == NULL) {
561 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
562 		(me, "unable to allocate a pointer to nsw config structure\n");
563 		return (NSCD_NO_MEMORY);
564 	}
565 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
566 		(me, "nsw config pointer = %p\n", nsw_cfg_p);
567 
568 	nsw_cfg->db_name = strdup(NSCD_NSW_DB_NAME(dbi));
569 	if (nsw_cfg->db_name == NULL) {
570 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
571 		(me, "unable to strdup the db name\n");
572 		return (NSCD_NO_MEMORY);
573 	}
574 
575 	/*
576 	 * set default frontend params and then call initf()
577 	 * to initialize or override
578 	 */
579 	nsw_cfg->fe_params.max_active_per_src = 10;
580 	nsw_cfg->fe_params.max_dormant_per_src = 1;
581 	nsw_cfg->fe_params.finders = _nscd_nss_finders;
582 	(void) (nscd_nss_db_initf[dbi])(&nsw_cfg->fe_params);
583 
584 	/*
585 	 * activate the new nscd_nsw_config_t
586 	 */
587 	*nsw_cfg_p = nsw_cfg;
588 	nscd_nsw_config[dbi] = (nscd_nsw_config_t **)_nscd_set(
589 	    (nscd_acc_data_t *)nscd_nsw_config[dbi],
590 	    (nscd_acc_data_t *)nsw_cfg_p);
591 
592 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
593 	(me, "nsw config %p activated\n", nsw_cfg);
594 
595 	return (NSCD_SUCCESS);
596 }
597 
598 nscd_rc_t
599 _nscd_init_all_nsw_config(void)
600 {
601 	nscd_rc_t	rc;
602 	int		i;
603 	char		*me = "_nscd_init_all_nsw_config";
604 
605 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
606 	(me, "initializing all nsw config\n");
607 
608 	for (i = 0; i < NSCD_NUM_DB; i++) {
609 		if ((rc = create_nsw_config(i)) != NSCD_SUCCESS)
610 			return (rc);
611 	}
612 
613 	return (NSCD_SUCCESS);
614 }
615 
616 static nscd_rc_t
617 init_nsw_be_info_db(int srci)
618 {
619 	nscd_db_t	*ret, **db_p;
620 	char		*me = "init_nsw_be_info_db";
621 
622 	ret = _nscd_alloc_db(NSCD_DB_SIZE_SMALL);
623 
624 	if (ret == NULL) {
625 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
626 		(me, "unable to allocate a nsw be info database\n");
627 		return (NSCD_NO_MEMORY);
628 	}
629 
630 	/* set up to reference count the backend info db */
631 	db_p = (nscd_db_t **)_nscd_alloc(NSCD_DATA_BACKEND_INFO_DB,
632 	    sizeof (nscd_db_t **), free_nsw_backend_info_db,
633 	    NSCD_ALLOC_RWLOCK);
634 
635 	if (db_p == NULL) {
636 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
637 		(me, "unable to allocate the pointer to the nsw "
638 		"be info database\n");
639 		return (NSCD_NO_MEMORY);
640 	}
641 
642 	*db_p = ret;
643 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
644 	(me, "backend database (db_p = %p, db = %p)\n", db_p, *db_p);
645 
646 	nscd_src_backend_db[srci] = (nscd_db_t **)_nscd_set(
647 	    (nscd_acc_data_t *)nscd_src_backend_db[srci],
648 	    (nscd_acc_data_t *)db_p);
649 
650 	return (NSCD_SUCCESS);
651 }
652 
653 nscd_rc_t
654 _nscd_init_all_nsw_be_info_db(void)
655 {
656 
657 	int		i;
658 	nscd_rc_t	rc;
659 	char		*me = "_nscd_init_all_nsw_be_info_db";
660 
661 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
662 	(me, "initializing all nsw be info databases\n");
663 
664 	for (i = 0; i < NSCD_NUM_SRC; i++) {
665 		if ((rc = init_nsw_be_info_db(i)) != NSCD_SUCCESS)
666 			return (rc);
667 	}
668 
669 	return (NSCD_SUCCESS);
670 }
671 
672 
673 nscd_rc_t
674 _nscd_alloc_nsw_config()
675 {
676 	nscd_nsw_config = calloc(NSCD_NUM_DB, sizeof (nscd_nsw_config_t **));
677 	if (nscd_nsw_config == NULL)
678 		return (NSCD_NO_MEMORY);
679 
680 	return (NSCD_SUCCESS);
681 }
682 
683 nscd_rc_t
684 _nscd_alloc_nsw_be_info_db()
685 {
686 	int	i;
687 
688 	_nscd_cfg_num_nsw_src_all = _nscd_cfg_num_nsw_src +
689 	    NSCD_NUM_SRC_FOREIGN;
690 	nscd_src_backend_db = calloc(NSCD_NUM_SRC, sizeof (nscd_db_t **));
691 	if (nscd_src_backend_db == NULL)
692 		return (NSCD_NO_MEMORY);
693 	nscd_src_backend_db_loaded = calloc(NSCD_NUM_SRC, sizeof (int));
694 	if (nscd_src_backend_db_loaded == NULL) {
695 		free(nscd_src_backend_db);
696 		return (NSCD_NO_MEMORY);
697 	}
698 
699 	/* also allocate/init the nsswitch source index/name array */
700 	_nscd_cfg_nsw_src_all = (nscd_cfg_id_t *)calloc(
701 	    _nscd_cfg_num_nsw_src_all + 1, sizeof (nscd_cfg_id_t));
702 	for (i = 0; i < _nscd_cfg_num_nsw_src_all + 1; i++)
703 		(_nscd_cfg_nsw_src_all + i)->index = -1;
704 
705 	(void) memcpy(_nscd_cfg_nsw_src_all, _nscd_cfg_nsw_src,
706 	    _nscd_cfg_num_nsw_src * sizeof (nscd_cfg_id_t));
707 	return (NSCD_SUCCESS);
708 }
709 
710 nscd_rc_t
711 _nscd_populate_nsw_backend_info()
712 {
713 	int		i;
714 	nscd_rc_t	rc;
715 
716 	for (i = 0; i < NSCD_NUM_SRC; i++) {
717 		if (NSCD_NSW_SRC_NAME(i) == NULL)
718 			continue;
719 		rc = _nscd_populate_nsw_backend_info_db(i);
720 		if (rc != NSCD_SUCCESS)
721 		return (rc);
722 	}
723 
724 	return (NSCD_SUCCESS);
725 }
726 
727 /*
728  * The following defines nscd's own lookup and delete functions
729  * that are to be stored in nss_backend_finder_t which is used
730  * by _nscd_populate_nsw_backend_info_db() to initialize the
731  * various nss backend instances
732  */
733 
734 static const int  dlopen_version  = 1;
735 #ifndef NSS_DLOPEN_FORMAT
736 #define	NSS_DLOPEN_FORMAT "nss_%s.so.%d"
737 #endif
738 #ifndef NSS_DLSYM_FORMAT
739 #define	NSS_DLSYM_FORMAT   "_nss_%s_%s_constr"
740 #define	NSS_DLSYM_FORMAT_V "_nss_%s_version"
741 #endif
742 static const char dlopen_format[] = NSS_DLOPEN_FORMAT;
743 static const char dlsym_format [] = NSS_DLSYM_FORMAT;
744 static const char dlsym_format_v [] = NSS_DLSYM_FORMAT_V;
745 static const size_t  format_maxlen   = sizeof (dlsym_format);
746 
747 /*ARGSUSED*/
748 static nss_backend_constr_t
749 _nscd_per_src_lookup(void *handle, const char *db_name, const char *src_name,
750 	void **delete_privp)
751 {
752 	char			*name;
753 	void			*dlhandle;
754 	void			*sym;
755 	size_t			len;
756 	nss_backend_constr_t	res = NULL;
757 
758 	len = format_maxlen + strlen(src_name);
759 	if (db_name != NULL)
760 		len += strlen(db_name);
761 	name = alloca(len);
762 	dlhandle = handle;
763 	if ((dlhandle = handle) == NULL) {
764 		(void) sprintf(name, dlopen_format, src_name, dlopen_version);
765 		dlhandle = dlopen(name, RTLD_LAZY);
766 	}
767 
768 	if (dlhandle != NULL) {
769 		if (db_name != NULL)
770 			(void) sprintf(name, dlsym_format, src_name, db_name);
771 		else
772 			(void) sprintf(name, dlsym_format_v, src_name);
773 		if ((sym = dlsym(dlhandle, name)) == 0) {
774 			if (handle == NULL)
775 				(void) dlclose(dlhandle);
776 		} else {
777 			*delete_privp = dlhandle;
778 			res = (nss_backend_constr_t)sym;
779 		}
780 	}
781 	return (res);
782 }
783 
784 /*ARGSUSED*/
785 static void
786 _nscd_per_src_delete(void *delete_priv, nss_backend_constr_t dummy)
787 {
788 	(void) dlclose(delete_priv);
789 }
790