xref: /titanic_52/usr/src/cmd/nscd/nscd_nswconfig.c (revision a83cadce5d3331b64803bfc641036cec23602c74)
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 <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 16 user-defined nsswitch sources/backends)
76  */
77 #define		NSCD_NUM_SRC_UDEF 16
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 
197 	for (i = 0; i < NSCD_NUM_DB; i++) {
198 
199 		if (nscd_nsw_config[i] == NULL)
200 			continue;
201 
202 		nsw_cfg = *nscd_nsw_config[i];
203 		dbn = NSCD_NSW_DB_NAME(i);
204 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
205 		(me, "adding backend info for <%s : %s>\n", src, dbn);
206 
207 		(void) memset(&be_info, 0, sizeof (be_info));
208 
209 		for (bf = nsw_cfg->fe_params.finders;  bf != 0;
210 				bf = bf->next) {
211 			nss_backend_constr_t c;
212 
213 			c = (*bf->lookup)(handle, dbn, src, &handle);
214 
215 			if (c != 0) {
216 				be_info.be_constr = c;
217 				be_info.finder = bf;
218 				be_info.finder_priv = handle;
219 				break;
220 			}
221 		}
222 		if (be_info.be_constr == NULL) {
223 			/*
224 			 * Couldn't find the backend anywhere.
225 			 * This is fine, some backend just don't
226 			 * support certain databases.
227 			 */
228 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
229 			(me, "unable to find backend info "
230 				"for <%s : %s>\n", src, dbn);
231 		}
232 
233 		size = sizeof (nscd_be_info_t);
234 
235 		db_entry = _nscd_alloc_db_entry(NSCD_DATA_BACKEND_INFO,
236 				dbn, size, 1, 1);
237 
238 		if (db_entry == NULL) {
239 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
240 			(me, "unable to allocate db entry for "
241 				"<%s : %s>\n", src, dbn);
242 			return (NSCD_NO_MEMORY);
243 		}
244 
245 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
246 		(me, "adding be db entry %p for <%s : %s> to db %p: "
247 			"constr = %p\n", db_entry, src, dbn,
248 			*nscd_src_backend_db[srci], be_info.be_constr);
249 
250 		bi = (nscd_be_info_t *)*(db_entry->data_array);
251 		*bi = be_info;
252 
253 		(void) _nscd_wrlock((nscd_acc_data_t *)
254 				nscd_src_backend_db[srci]);
255 		nscd_src_backend_db_loaded[srci] = 1;
256 		(void) _nscd_add_db_entry(*nscd_src_backend_db[srci],
257 			dbn, db_entry, NSCD_ADD_DB_ENTRY_LAST);
258 		(void) _nscd_rw_unlock((nscd_acc_data_t *)
259 				nscd_src_backend_db[srci]);
260 	}
261 
262 	return (NSCD_SUCCESS);
263 }
264 
265 /*
266  * create data structures (used by the switch engine) based
267  * on the input switch policy configuration and database
268  * name and indexes
269  */
270 nscd_rc_t
271 _nscd_create_sw_struct(
272 	int				dbi,
273 	int				compat_basei,
274 	const char			*dbn,
275 	const char			*cfgstr,
276 	void				*swcfgv1,
277 	nscd_nsw_params_t		*params)
278 {
279 	char				*me = "_nscd_create_sw_struct";
280 	nscd_rc_t			rc = NSCD_SUCCESS;
281 	nscd_nsw_config_t		*nsw_cfg = NULL;
282 	nscd_nsw_config_t		**nsw_cfg_p = NULL;
283 	struct __nsw_switchconfig_v1	*swcfg = NULL;
284 	struct __nsw_lookup_v1		*lkp;
285 	enum __nsw_parse_err		err;
286 	int				maxsrc;
287 	int				*src_idx_a = NULL;
288 	int				j, k;
289 
290 	/*
291 	 * if the nsw config string has been parsed into
292 	 * a struct __nsw_switchconfig_v1, use it. If not,
293 	 * create the struct.
294 	 */
295 	if (swcfgv1 != NULL)
296 		swcfg = (struct __nsw_switchconfig_v1 *)swcfgv1;
297 	else {
298 		char	*cstr;
299 
300 		cstr = strdup(cfgstr);
301 		if (cstr == NULL)
302 			return (NSCD_NO_MEMORY);
303 
304 		/*
305 		 * parse the nsw config string and create
306 		 * a struct __nsw_switchconfig_v1
307 		 */
308 		swcfg = _nsw_getoneconfig_v1(dbn, cstr, &err);
309 		free(cstr);
310 		if (swcfg == NULL) {
311 			rc = NSCD_CFG_SYNTAX_ERROR;
312 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
313 			(me, "error: unable to process nsw config string\n");
314 			goto error_exit;
315 		}
316 	}
317 
318 	/* allocate the space for a nscd_nsw_config_t */
319 	nsw_cfg = calloc(1, sizeof (nscd_nsw_config_t));
320 	if (nsw_cfg == NULL) {
321 		rc = NSCD_NO_MEMORY;
322 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
323 		(me, "error: unable to allocate an nscd_nsw_config_t\n");
324 		goto error_exit;
325 	}
326 
327 	/* need to know how many backends (sources) */
328 	maxsrc = swcfg->num_lookups;
329 	nsw_cfg->max_src = maxsrc;
330 
331 	/*
332 	 * allocate an array to store the index for each
333 	 * backend (source)
334 	 */
335 	src_idx_a = calloc(1, maxsrc * sizeof (int));
336 	if (src_idx_a == NULL) {
337 		rc = NSCD_NO_MEMORY;
338 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
339 		(me, "error: unable to allocate an array for source index\n");
340 		goto error_exit;
341 	}
342 
343 	/*
344 	 * set the index for each backend (source)
345 	 */
346 	lkp = swcfg->lookups;
347 	for (j = 0; j < maxsrc; j++) {
348 		char *usrc;
349 
350 		for (k = 0; k < NSCD_NUM_SRC &&
351 			NSCD_NSW_SRC_NAME(k) != NULL &&
352 			strcmp(lkp->service_name,
353 			NSCD_NSW_SRC_NAME(k)) != 0; k++);
354 
355 		if (k < NSCD_NUM_SRC &&
356 			nscd_src_backend_db_loaded[k] == 0) {
357 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
358 			(me, "unknown nsw source name %s\n",
359 			lkp->service_name);
360 			usrc = strdup(lkp->service_name);
361 			if (usrc == NULL) {
362 				rc = NSCD_NO_MEMORY;
363 				_NSCD_LOG(NSCD_LOG_CONFIG,
364 					NSCD_LOG_LEVEL_ERROR)
365 				(me, "unable to strdup() source name\n");
366 				goto error_exit;
367 			}
368 			NSCD_NSW_SRC_NAME(k) = usrc;
369 
370 			rc = _nscd_populate_nsw_backend_info_db(k);
371 			if (rc != NSCD_SUCCESS) {
372 				free(usrc);
373 				NSCD_NSW_SRC_NAME(k) = NULL;
374 				goto error_exit;
375 			}
376 		} else if (NSCD_NSW_SRC_NAME(k) == NULL) {
377 			/*
378 			 * number of user-defined source exceeded
379 			 */
380 			rc = NSCD_CFG_SYNTAX_ERROR;
381 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
382 			(me, "error: number of user_defined source exceeded\n");
383 
384 			goto error_exit;
385 		}
386 
387 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
388 			(me, "setting source index array [%d] = %d (%s)\n",
389 			j, k, lkp->service_name);
390 
391 		src_idx_a[j] = k;
392 
393 		lkp = lkp->next;
394 		if (lkp == NULL) break;
395 
396 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
397 		(me, "number of nsw sources = %d\n", nsw_cfg->max_src);
398 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
399 		(me, "next nsw source is %s\n", lkp->service_name);
400 	}
401 
402 	/* set it up to reference count the switch policy config */
403 	nsw_cfg_p = (nscd_nsw_config_t **)_nscd_alloc(
404 			NSCD_DATA_NSW_CONFIG,
405 			sizeof (nscd_nsw_config_t **),
406 			free_nscd_nsw_config,
407 			NSCD_ALLOC_RWLOCK);
408 
409 	if (nsw_cfg_p == NULL) {
410 		rc = NSCD_NO_MEMORY;
411 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
412 		(me, "unable to allocate a new nsw config DB\n");
413 		goto error_exit;
414 	}
415 	*nsw_cfg_p = nsw_cfg;
416 
417 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
418 	(me, "new nsw config DB %p allocated\n", nsw_cfg_p);
419 
420 	/* save all the data in the new nscd_nsw_config_t */
421 	nsw_cfg->db_name = strdup(dbn);
422 	nsw_cfg->nsw_cfg_str = strdup(cfgstr);
423 	if (nsw_cfg->db_name == NULL || nsw_cfg->nsw_cfg_str == NULL) {
424 		rc = NSCD_NO_MEMORY;
425 		goto error_exit;
426 	}
427 
428 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
429 	(me, "switch policy \"%s\" for database is \"%s\"\n",
430 		nsw_cfg->db_name, nsw_cfg->nsw_cfg_str);
431 
432 	nsw_cfg->nsw_config = swcfg;
433 	nsw_cfg->src_idx = src_idx_a;
434 
435 	/*
436 	 * set default frontend params and if necessary call initf()
437 	 * to initialize or override
438 	 */
439 	nsw_cfg->fe_params.max_active_per_src = 10;
440 	nsw_cfg->fe_params.max_dormant_per_src = 1;
441 	nsw_cfg->fe_params.finders = _nscd_nss_finders;
442 	if (params != NULL) {
443 		nsw_cfg->fe_params = params->p;
444 
445 		if (params->p.flags & NSS_USE_DEFAULT_CONFIG) {
446 			params->nswcfg = nsw_cfg_p;
447 			/*
448 			 * this nsw_cfg is not meant to last long, no need
449 			 * to set up the nsw state and getent bases, just
450 			 * exit with NSCD_SUCCESS
451 			 */
452 			nsw_cfg->nobase = 1;
453 			goto error_exit;
454 		}
455 	} else
456 		(void) (nscd_nss_db_initf[dbi])(&nsw_cfg->fe_params);
457 
458 	/*
459 	 * activate the new nscd_nsw_config_t, the old one
460 	 * will either be deleted or left on the side (and be
461 	 * deleted eventually)
462 	 */
463 	nscd_nsw_config[dbi] = (nscd_nsw_config_t **)_nscd_set(
464 		(nscd_acc_data_t *)nscd_nsw_config[dbi],
465 		(nscd_acc_data_t *)nsw_cfg_p);
466 
467 	/*
468 	 * also create a new nsw state base
469 	 */
470 	if ((rc = _nscd_init_nsw_state_base(dbi, compat_basei, 1)) !=
471 		NSCD_SUCCESS) {
472 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
473 		(me, "unable to initialize a nsw state base(%d)\n", dbi);
474 		goto error_exit;
475 	}
476 
477 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
478 	(me, "new nsw state base(%d) %p created\n", dbi,
479 		nscd_nsw_state_base[dbi]);
480 
481 	/*
482 	 * also create a new getent context base
483 	 */
484 	if ((rc = _nscd_init_getent_ctx_base(dbi, 1)) != NSCD_SUCCESS) {
485 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
486 		(me, "unable to initialize a getent context base(%d)\n", dbi);
487 		goto error_exit;
488 	}
489 
490 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
491 	(me, "new getent context base(%d) %p created\n", dbi,
492 	nscd_getent_ctx_base[dbi]);
493 
494 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
495 	(me, "new nsw config created (database = %s, "
496 	"config = %s)\n", dbn, cfgstr);
497 
498 
499 	error_exit:
500 
501 	if (rc != NSCD_SUCCESS) {
502 
503 		if (swcfgv1 == NULL && swcfg != NULL)
504 			(void) __nsw_freeconfig_v1(swcfg);
505 		if (src_idx_a != NULL)
506 			free(src_idx_a);
507 		if (nsw_cfg_p)
508 			free(nsw_cfg_p);
509 		if (nsw_cfg != NULL) {
510 			if (nsw_cfg->db_name != NULL)
511 				free(nsw_cfg->db_name);
512 			if (nsw_cfg->nsw_cfg_str != NULL)
513 				free(nsw_cfg->nsw_cfg_str);
514 			free(nsw_cfg);
515 		}
516 
517 		return (rc);
518 	} else
519 		return (NSCD_SUCCESS);
520 }
521 
522 static nscd_rc_t
523 create_nsw_config(int dbi)
524 {
525 
526 	nscd_nsw_config_t	*nsw_cfg = NULL;
527 	nscd_nsw_config_t	**nsw_cfg_p = NULL;
528 	char			*me = "create_nsw_config";
529 
530 	/*
531 	 * if pseudo-databases (initf function not defined),
532 	 * don't bother now
533 	 */
534 	if (nscd_nss_db_initf[dbi] == NULL)
535 		return (NSCD_SUCCESS);
536 
537 	/* allocate the space for a nscd_nsw_config_t */
538 	nsw_cfg = calloc(1, sizeof (nscd_nsw_config_t));
539 	if (nsw_cfg == NULL) {
540 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
541 		(me, "unable to allocate a nsw config structure\n");
542 		return (NSCD_NO_MEMORY);
543 	}
544 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
545 	(me, "nsw config structure %pallocated\n", nsw_cfg);
546 
547 	nsw_cfg_p = (nscd_nsw_config_t **)_nscd_alloc(
548 		NSCD_DATA_NSW_CONFIG,
549 		sizeof (nscd_nsw_config_t **),
550 		free_nscd_nsw_config,
551 		NSCD_ALLOC_RWLOCK);
552 
553 	if (nsw_cfg_p == NULL) {
554 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
555 		(me, "unable to allocate a pointer to nsw config structure\n");
556 		return (NSCD_NO_MEMORY);
557 	}
558 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
559 		(me, "nsw config pointer = %p\n", nsw_cfg_p);
560 
561 	nsw_cfg->db_name = strdup(NSCD_NSW_DB_NAME(dbi));
562 	if (nsw_cfg->db_name == NULL) {
563 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
564 		(me, "unable to strdup the db name\n");
565 		return (NSCD_NO_MEMORY);
566 	}
567 
568 	/*
569 	 * set default frontend params and then call initf()
570 	 * to initialize or override
571 	 */
572 	nsw_cfg->fe_params.max_active_per_src = 10;
573 	nsw_cfg->fe_params.max_dormant_per_src = 1;
574 	nsw_cfg->fe_params.finders = _nscd_nss_finders;
575 	(void) (nscd_nss_db_initf[dbi])(&nsw_cfg->fe_params);
576 
577 	/*
578 	 * activate the new nscd_nsw_config_t
579 	 */
580 	*nsw_cfg_p = nsw_cfg;
581 	nscd_nsw_config[dbi] = (nscd_nsw_config_t **)_nscd_set(
582 		(nscd_acc_data_t *)nscd_nsw_config[dbi],
583 		(nscd_acc_data_t *)nsw_cfg_p);
584 
585 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
586 	(me, "nsw config %p activated\n", nsw_cfg);
587 
588 	return (NSCD_SUCCESS);
589 }
590 
591 nscd_rc_t
592 _nscd_init_all_nsw_config(void)
593 {
594 	nscd_rc_t	rc;
595 	int		i;
596 	char		*me = "_nscd_init_all_nsw_config";
597 
598 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
599 	(me, "initializing all nsw config\n");
600 
601 	for (i = 0; i < NSCD_NUM_DB; i++) {
602 		if ((rc = create_nsw_config(i)) != NSCD_SUCCESS)
603 			return (rc);
604 	}
605 
606 	return (NSCD_SUCCESS);
607 }
608 
609 static nscd_rc_t
610 init_nsw_be_info_db(int srci)
611 {
612 	nscd_db_t	*ret, **db_p;
613 	char		*me = "init_nsw_be_info_db";
614 
615 	ret = _nscd_alloc_db(NSCD_DB_SIZE_SMALL);
616 
617 	if (ret == NULL) {
618 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
619 		(me, "unable to allocate a nsw be info database\n");
620 		return (NSCD_NO_MEMORY);
621 	}
622 
623 	/* set up to reference count the backend info db */
624 	db_p = (nscd_db_t **)
625 		_nscd_alloc(NSCD_DATA_BACKEND_INFO_DB,
626 		sizeof (nscd_db_t **),
627 		free_nsw_backend_info_db,
628 		NSCD_ALLOC_RWLOCK);
629 
630 	if (db_p == NULL) {
631 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
632 		(me, "unable to allocate the pointer to the nsw "
633 		"be info database\n");
634 		return (NSCD_NO_MEMORY);
635 	}
636 
637 	*db_p = ret;
638 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
639 	(me, "backend database (db_p = %p, db = %p)\n", db_p, *db_p);
640 
641 	nscd_src_backend_db[srci] = (nscd_db_t **)_nscd_set(
642 		(nscd_acc_data_t *)nscd_src_backend_db[srci],
643 		(nscd_acc_data_t *)db_p);
644 
645 	return (NSCD_SUCCESS);
646 }
647 
648 nscd_rc_t
649 _nscd_init_all_nsw_be_info_db(void)
650 {
651 
652 	int		i;
653 	nscd_rc_t	rc;
654 	char		*me = "_nscd_init_all_nsw_be_info_db";
655 
656 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
657 	(me, "initializing all nsw be info databases\n");
658 
659 	for (i = 0; i < NSCD_NUM_SRC; i++) {
660 		if ((rc = init_nsw_be_info_db(i)) != NSCD_SUCCESS)
661 			return (rc);
662 	}
663 
664 	return (NSCD_SUCCESS);
665 }
666 
667 
668 nscd_rc_t
669 _nscd_alloc_nsw_config()
670 {
671 	nscd_nsw_config = calloc(NSCD_NUM_DB, sizeof (nscd_nsw_config_t **));
672 	if (nscd_nsw_config == NULL)
673 		return (NSCD_NO_MEMORY);
674 
675 	return (NSCD_SUCCESS);
676 }
677 
678 nscd_rc_t
679 _nscd_alloc_nsw_be_info_db()
680 {
681 	int	i;
682 
683 	_nscd_cfg_num_nsw_src_all = _nscd_cfg_num_nsw_src + NSCD_NUM_SRC_UDEF;
684 	nscd_src_backend_db = calloc(NSCD_NUM_SRC, sizeof (nscd_db_t **));
685 	if (nscd_src_backend_db == NULL)
686 		return (NSCD_NO_MEMORY);
687 	nscd_src_backend_db_loaded = calloc(NSCD_NUM_SRC, sizeof (int));
688 	if (nscd_src_backend_db_loaded == NULL) {
689 		free(nscd_src_backend_db);
690 		return (NSCD_NO_MEMORY);
691 	}
692 
693 	/* also allocate/init the nsswitch source index/name array */
694 	_nscd_cfg_nsw_src_all = (nscd_cfg_id_t *)calloc(
695 		_nscd_cfg_num_nsw_src_all + 1, sizeof (nscd_cfg_id_t));
696 	for (i = 0; i < _nscd_cfg_num_nsw_src_all + 1; i++)
697 		(_nscd_cfg_nsw_src_all + i)->index = -1;
698 
699 	(void) memcpy(_nscd_cfg_nsw_src_all, _nscd_cfg_nsw_src,
700 			_nscd_cfg_num_nsw_src * sizeof (nscd_cfg_id_t));
701 	return (NSCD_SUCCESS);
702 }
703 
704 nscd_rc_t
705 _nscd_populate_nsw_backend_info()
706 {
707 	int		i;
708 	nscd_rc_t	rc;
709 
710 	for (i = 0; i < NSCD_NUM_SRC; i++) {
711 		if (NSCD_NSW_SRC_NAME(i) == NULL)
712 			continue;
713 		rc = _nscd_populate_nsw_backend_info_db(i);
714 		if (rc != NSCD_SUCCESS)
715 		return (rc);
716 	}
717 
718 	return (NSCD_SUCCESS);
719 }
720 
721 /*
722  * The following defines nscd's own lookup and delete functions
723  * that are to be stored in nss_backend_finder_t which is used
724  * by _nscd_populate_nsw_backend_info_db() to initialize the
725  * various nss backend instances
726  */
727 
728 static const int  dlopen_version  = 1;
729 #ifndef NSS_DLOPEN_FORMAT
730 #define	NSS_DLOPEN_FORMAT "nss_%s.so.%d"
731 #endif
732 #ifndef NSS_DLSYM_FORMAT
733 #define	NSS_DLSYM_FORMAT "_nss_%s_%s_constr"
734 #endif
735 static const char dlopen_format[] = NSS_DLOPEN_FORMAT;
736 static const char dlsym_format [] = NSS_DLSYM_FORMAT;
737 static const size_t  format_maxlen   = sizeof (dlsym_format) - 4;
738 
739 /*ARGSUSED*/
740 static nss_backend_constr_t
741 _nscd_per_src_lookup(void *handle, const char *db_name, const char *src_name,
742 	void **delete_privp)
743 {
744 	char			*name;
745 	void			*dlhandle;
746 	void			*sym;
747 	size_t			len;
748 	nss_backend_constr_t	res = NULL;
749 
750 	len = format_maxlen + strlen(db_name) + strlen(src_name);
751 	name = alloca(len);
752 	dlhandle = handle;
753 	if ((dlhandle = handle) == NULL) {
754 		(void) sprintf(name, dlopen_format, src_name, dlopen_version);
755 		dlhandle = dlopen(name, RTLD_LAZY);
756 	}
757 
758 	if (dlhandle != NULL) {
759 		(void) sprintf(name, dlsym_format, src_name, db_name);
760 		if ((sym = dlsym(dlhandle, name)) == 0) {
761 			if (handle == NULL)
762 				(void) dlclose(dlhandle);
763 		} else {
764 			*delete_privp = dlhandle;
765 			res = (nss_backend_constr_t)sym;
766 		}
767 	}
768 	return (res);
769 }
770 
771 /*ARGSUSED*/
772 static void
773 _nscd_per_src_delete(void *delete_priv, nss_backend_constr_t dummy)
774 {
775 	(void) dlclose(delete_priv);
776 }
777