xref: /illumos-gate/usr/src/cmd/nscd/nscd_config.c (revision fb2a9bae0030340ad72b9c26ba1ffee2ee3cafec)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <locale.h>		/* gettext */
29 #include <dlfcn.h>
30 #include <string.h>
31 #include <sys/varargs.h>
32 #include <errno.h>
33 #include "nscd_db.h"
34 #include "nscd_config.h"
35 #include "nscd_cfgdef.h"
36 #include "nscd_log.h"
37 
38 typedef struct {
39 	rwlock_t	*global;
40 	rwlock_t	*alldb;
41 	rwlock_t	*nswdb;
42 } nscd_cfg_lock_t;
43 
44 static rwlock_t		cfg_paramDB_rwlock = DEFAULTRWLOCK;
45 static nscd_db_t	*cfg_paramDB = NULL;
46 
47 static	nscd_cfg_global_data_t 	*nscd_cfg_global_current;
48 static	nscd_cfg_nsw_db_data_t	*nscd_cfg_nsw_db_data_current;
49 static	nscd_cfg_nsw_db_data_t	*nscd_cfg_nsw_alldb_current;
50 static	rwlock_t		*nscd_cfg_global_rwlock;
51 static	rwlock_t		*nscd_cfg_nsw_db_data_rwlock;
52 static	rwlock_t		*nscd_cfg_nsw_alldb_rwlock;
53 
54 extern	int			_nscd_cfg_num_nsw_src_all;
55 extern	nscd_cfg_id_t		*_nscd_cfg_nsw_src_all;
56 
57 nscd_cfg_error_t *
58 _nscd_cfg_make_error(
59 	nscd_rc_t	rc,
60 	char		*msg)
61 {
62 
63 	nscd_cfg_error_t	*ret;
64 	int			size, msglen;
65 
66 	msglen = (msg != NULL ? strlen(msg) + 1 : 0);
67 
68 	size = sizeof (nscd_cfg_error_t) + msglen;
69 
70 	ret = calloc(1, size);
71 	if (ret == NULL)
72 		return (NULL);
73 
74 	ret->rc = rc;
75 	if (msg != NULL) {
76 		ret->msg = (char *)ret +
77 		    sizeof (nscd_cfg_error_t);
78 		(void) memcpy(ret->msg, msg, msglen);
79 	}
80 
81 	return (ret);
82 }
83 
84 static nscd_rc_t
85 _nscd_cfg_get_list(
86 	nscd_cfg_list_t		**list,
87 	nscd_cfg_list_type_t	type)
88 {
89 	char			*me = "_nscd_cfg_get_list";
90 	int			i, num, size;
91 	nscd_cfg_id_t		*l;
92 	nscd_cfg_list_t 	*ret;
93 	nscd_cfg_param_desc_t	*pl;
94 	nscd_cfg_stat_desc_t	*sl;
95 	void			*p;
96 
97 	if (list == NULL) {
98 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
99 		(me, "invalid argument: list = %p\n", list);
100 
101 		return (NSCD_INVALID_ARGUMENT);
102 	}
103 	*list = NULL;
104 
105 	switch (type) {
106 	case NSCD_CFG_LIST_NSW_DB:
107 
108 		num = _nscd_cfg_num_nsw_db;
109 		l = &_nscd_cfg_nsw_db[0];
110 		break;
111 
112 	case NSCD_CFG_LIST_NSW_SRC:
113 
114 		num = _nscd_cfg_num_nsw_src_all;
115 		l = _nscd_cfg_nsw_src_all;
116 		break;
117 
118 	case NSCD_CFG_LIST_PARAM:
119 
120 		num = _nscd_cfg_num_param;
121 		pl = &_nscd_cfg_param_desc[0];
122 		break;
123 
124 	case NSCD_CFG_LIST_STAT:
125 
126 		num = _nscd_cfg_num_stat;
127 		sl = &_nscd_cfg_stat_desc[0];
128 		break;
129 
130 	default:
131 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
132 		(me, "invalid argument: type (%d)\n", type);
133 
134 		return (NSCD_INVALID_ARGUMENT);
135 		break;
136 	}
137 
138 	size =  sizeof (nscd_cfg_list_t) + sizeof (nscd_cfg_id_t *) * (num + 1);
139 
140 	ret = calloc(1, size);
141 	if (ret == NULL)
142 		return (NSCD_NO_MEMORY);
143 
144 	ret->num = num;
145 	p = (char *)ret + sizeof (nscd_cfg_list_t);
146 	ret->list = (nscd_cfg_id_t **)p;
147 
148 	if (type == NSCD_CFG_LIST_PARAM) {
149 		for (i = 0; i <= num; i++)
150 			ret->list[i] = (nscd_cfg_id_t *)&pl[i];
151 	} else if (type == NSCD_CFG_LIST_STAT) {
152 		for (i = 0; i <= num; i++)
153 			ret->list[i] = (nscd_cfg_id_t *)&sl[i];
154 	} else {
155 		for (i = 0; i <= num; i++)
156 			ret->list[i] = &l[i];
157 	}
158 
159 	*list = ret;
160 
161 	return (NSCD_SUCCESS);
162 }
163 
164 nscd_rc_t
165 _nscd_cfg_get_param_desc_list(
166 	nscd_cfg_param_desc_list_t **list)
167 {
168 	return (_nscd_cfg_get_list((nscd_cfg_list_t **)list,
169 	    NSCD_CFG_LIST_PARAM));
170 }
171 
172 /*
173  * FUNCTION: _nscd_cfg_create_paramDB
174  *
175  * Create the internal config parameter database
176  */
177 static nscd_db_t *
178 _nscd_cfg_create_paramDB()
179 {
180 
181 	nscd_db_t	*ret;
182 
183 	(void) rw_wrlock(&cfg_paramDB_rwlock);
184 
185 	ret = _nscd_alloc_db(NSCD_DB_SIZE_MEDIUM);
186 
187 	if (ret != NULL)
188 		cfg_paramDB = ret;
189 
190 	(void) rw_unlock(&cfg_paramDB_rwlock);
191 
192 	return (ret);
193 }
194 
195 /*
196  * FUNCTION: _nscd_cfg_add_index_entry
197  *
198  * Add a config index entry (a name to index mapping)
199  * to the internal configuration database.
200  */
201 static nscd_rc_t
202 _nscd_cfg_add_index_entry(
203 	char			*name,
204 	int			index,
205 	nscd_cfg_list_type_t	type)
206 {
207 	int		*idx;
208 	int		size;
209 	int		dbe_type;
210 	nscd_db_entry_t	*db_entry;
211 
212 	if (name == NULL)
213 		return (NSCD_INVALID_ARGUMENT);
214 
215 	if (type == NSCD_CFG_LIST_NSW_DB)
216 		dbe_type = NSCD_DATA_CFG_NSW_DB_INDEX;
217 	else if (type == NSCD_CFG_LIST_NSW_SRC)
218 		dbe_type = NSCD_DATA_CFG_NSW_SRC_INDEX;
219 	else if (type == NSCD_CFG_LIST_PARAM)
220 		dbe_type = NSCD_DATA_CFG_PARAM_INDEX;
221 	else if (type == NSCD_CFG_LIST_STAT)
222 		dbe_type = NSCD_DATA_CFG_STAT_INDEX;
223 
224 	size = sizeof (int);
225 
226 	db_entry = _nscd_alloc_db_entry(dbe_type, (const char *)name,
227 	    size, 1, 1);
228 	if (db_entry == NULL)
229 		return (NSCD_NO_MEMORY);
230 
231 	idx = (int *)*(db_entry->data_array);
232 	*idx = index;
233 
234 	(void) rw_wrlock(&cfg_paramDB_rwlock);
235 	(void) _nscd_add_db_entry(cfg_paramDB, name, db_entry,
236 	    NSCD_ADD_DB_ENTRY_FIRST);
237 	(void) rw_unlock(&cfg_paramDB_rwlock);
238 
239 	return (NSCD_SUCCESS);
240 }
241 
242 /*
243  * FUNCTION: _nscd_cfg_get_index
244  *
245  * Get the index of a config data item by searching the internal config
246  * database. Do not free the returned data.
247  */
248 static int
249 _nscd_cfg_get_index(
250 	char			*name,
251 	nscd_cfg_list_type_t	type)
252 {
253 	int			index = -1, dbe_type;
254 	const nscd_db_entry_t	*db_entry;
255 
256 	if (name == NULL)
257 		return (-1);
258 
259 	if (type == NSCD_CFG_LIST_NSW_DB)
260 		dbe_type = NSCD_DATA_CFG_NSW_DB_INDEX;
261 	else if (type == NSCD_CFG_LIST_NSW_SRC)
262 		dbe_type = NSCD_DATA_CFG_NSW_SRC_INDEX;
263 	else if (type == NSCD_CFG_LIST_PARAM)
264 		dbe_type = NSCD_DATA_CFG_PARAM_INDEX;
265 	else if (type == NSCD_CFG_LIST_STAT)
266 		dbe_type = NSCD_DATA_CFG_STAT_INDEX;
267 	else
268 		return (-1);
269 
270 	db_entry = _nscd_get_db_entry(cfg_paramDB, dbe_type,
271 	    (const char *)name, NSCD_GET_FIRST_DB_ENTRY, 0);
272 
273 	if (db_entry != NULL)
274 		index = *(int *)*(db_entry->data_array);
275 
276 	return (index);
277 }
278 
279 static nscd_rc_t
280 _nscd_cfg_verify_group_info(
281 	nscd_cfg_group_info_t	*g_info,
282 	nscd_cfg_param_desc_t	*gdesc)
283 {
284 
285 	char			*me = "_nscd_cfg_verify_group_info";
286 	void			*vp;
287 	nscd_cfg_group_info_t	*gi;
288 
289 	if (_nscd_cfg_flag_is_set(gdesc->pflag, NSCD_CFG_PFLAG_GLOBAL)) {
290 		vp = (char *)&nscd_cfg_global_default +
291 		    gdesc->g_offset;
292 		gi = (nscd_cfg_group_info_t *)vp;
293 	} else {
294 		vp = (char *)&nscd_cfg_nsw_db_data_default +
295 		    gdesc->g_offset;
296 		gi = (nscd_cfg_group_info_t *)vp;
297 
298 	}
299 
300 	if (g_info->num_param == gi->num_param &&
301 	    _nscd_cfg_bitmap_is_equal(g_info->bitmap, gi->bitmap))
302 		return (NSCD_SUCCESS);
303 
304 	_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
305 	(me, "ERROR: group (%s) info mismatched: group info "
306 	    "(%d, %#6.4x) not equal to that of default configuration data "
307 	    "(%d, %#6.4x)\n", gdesc->id.name, g_info->num_param,
308 	    _nscd_cfg_bitmap_value(g_info->bitmap), gi->num_param,
309 	    _nscd_cfg_bitmap_value(gi->bitmap));
310 
311 	return (NSCD_CFG_PARAM_DESC_ERROR);
312 
313 }
314 
315 
316 static nscd_rc_t
317 _nscd_cfg_init_nsw()
318 {
319 	char			*me = "_nscd_cfg_init_nsw";
320 	int			i, j, idx, rc, num;
321 	nscd_cfg_id_t		*id;
322 	nscd_cfg_list_type_t	type[2] = { NSCD_CFG_LIST_NSW_DB,
323 					NSCD_CFG_LIST_NSW_SRC };
324 
325 	nscd_cfg_id_t		*list[2] = { _nscd_cfg_nsw_db, NULL};
326 
327 	list[1] = _nscd_cfg_nsw_src_all;
328 
329 	for (j = 0; j < 2; j++) {
330 
331 		if (j == 0)
332 			num = _nscd_cfg_num_nsw_db + 1;
333 		else
334 			num = _nscd_cfg_num_nsw_src_all;
335 
336 		for (i = 0; i < num; i++) {
337 
338 			/*
339 			 * _nscd_cfg_nsw_alldb is the id for the
340 			 * special ALLDB (defaults for all db)
341 			 */
342 			if (j == 0 && i == _nscd_cfg_num_nsw_db) {
343 				id = &_nscd_cfg_nsw_alldb;
344 				idx = NSCD_CFG_NSW_ALLDB_INDEX;
345 			} else {
346 				id = &(list[j])[i];
347 				id->index = idx = i;
348 			}
349 
350 			if (id->name == NULL)
351 				continue;
352 
353 			if ((rc = _nscd_cfg_add_index_entry(id->name,
354 			    idx, type[j])) != NSCD_SUCCESS) {
355 
356 				_NSCD_LOG(NSCD_LOG_CONFIG,
357 				    NSCD_LOG_LEVEL_ERROR)
358 				(me, "unable to add index entry for "
359 				"nsswitch entry %s\n", id->name);
360 
361 				_nscd_free_db(cfg_paramDB);
362 				return (rc);
363 			}
364 		}
365 	}
366 
367 	return (NSCD_SUCCESS);
368 }
369 
370 static nscd_rc_t
371 _nscd_cfg_init_param()
372 {
373 	char			*me = "_nscd_cfg_init_param";
374 	int			i, gi, fn = 0;
375 	nscd_cfg_id_t		*id;
376 	nscd_cfg_param_desc_t	*desc, *gdesc = NULL;
377 	nscd_cfg_group_info_t	g_info;
378 	nscd_cfg_list_type_t	type = NSCD_CFG_LIST_PARAM;
379 	nscd_rc_t		rc;
380 	void			*nfunc, *vfunc;
381 
382 	if (_nscd_cfg_create_paramDB() == NULL)
383 		return (NSCD_NO_MEMORY);
384 
385 	desc = &_nscd_cfg_param_desc[0];
386 
387 	/*
388 	 * need to loop to the last (+1) param description
389 	 * which is a fake group and which marks the end
390 	 * of list. It is used to signal the end of the
391 	 * previous group so that the proper data will be
392 	 * set for that group
393 	 */
394 	for (i = 0; i < _nscd_cfg_num_param + 1; i++, desc++) {
395 
396 		id = (nscd_cfg_id_t *)desc;
397 
398 		if (_nscd_cfg_flag_is_set(desc->pflag,
399 		    NSCD_CFG_PFLAG_GROUP)) {
400 
401 			if (gdesc != NULL) {
402 				g_info.num_param = fn;
403 				gdesc->p_fn = fn;
404 
405 				if ((rc = _nscd_cfg_verify_group_info(
406 				    &g_info, gdesc)) != NSCD_SUCCESS)
407 					return (rc);
408 			}
409 
410 			gi = i;
411 			fn = 0;
412 			gdesc = desc;
413 			g_info.bitmap = NSCD_CFG_BITMAP_ZERO;
414 
415 			/*
416 			 * set the notify/verify functions
417 			 */
418 			nfunc = (void *)gdesc->notify;
419 			vfunc = (void *)gdesc->verify;
420 		} else {
421 			if (i == 0) {
422 
423 				_NSCD_LOG(NSCD_LOG_CONFIG,
424 				    NSCD_LOG_LEVEL_ERROR)
425 				(me, "ERROR: first parameter "
426 				"description is not for a group\n");
427 
428 				return (NSCD_CFG_PARAM_DESC_ERROR);
429 			}
430 
431 			/*
432 			 * set bitmap: the rightmost bit represents
433 			 * the first member (index = 0) in the group,
434 			 * the next bit is for the second member
435 			 * (index = 1), and so on
436 			 */
437 			_nscd_cfg_bitmap_set_nth(g_info.bitmap, fn);
438 
439 			desc->p_fn = fn++;
440 
441 			/*
442 			 * set the notify/verify functions
443 			 */
444 			if (desc->notify == NSCD_CFG_FUNC_NOTIFY_AS_GROUP) {
445 				(void) memcpy(&desc->notify, &nfunc,
446 				    sizeof (void *));
447 			}
448 			if (desc->verify == NSCD_CFG_FUNC_VERIFY_AS_GROUP) {
449 				(void) memcpy(&desc->verify, &vfunc,
450 				    sizeof (void *));
451 			}
452 		}
453 
454 		/* if end of list reached, we are done */
455 		if (i == _nscd_cfg_num_param)
456 			break;
457 
458 		desc->g_index = gi;
459 
460 		id->index = i;
461 
462 		if ((rc = _nscd_cfg_add_index_entry(id->name,
463 		    i, type)) != NSCD_SUCCESS) {
464 
465 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
466 			(me, "unable to add index entry for parameter "
467 			"%s\n", id->name);
468 
469 			_nscd_free_db(cfg_paramDB);
470 			return (rc);
471 		} else {
472 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
473 			(me, "index entry for parameter "
474 			"%s added\n", id->name);
475 		}
476 	}
477 
478 	return (_nscd_cfg_init_nsw());
479 }
480 
481 static nscd_rc_t
482 _nscd_cfg_init_stat()
483 {
484 	char			*me = "_nscd_cfg_init_stat";
485 	int			i, gi, fn = 0;
486 	nscd_cfg_id_t		*id;
487 	nscd_cfg_stat_desc_t	*desc, *gdesc = NULL;
488 	nscd_cfg_group_info_t	g_info;
489 	nscd_cfg_list_type_t	type = NSCD_CFG_LIST_STAT;
490 	nscd_rc_t		rc;
491 	void			*gsfunc;
492 
493 	desc = &_nscd_cfg_stat_desc[0];
494 
495 	/*
496 	 * need to loop to the last (+1) stat description
497 	 * which is a fake group and which marks the end
498 	 * of list. It is used to signal the end of the
499 	 * previous group so that the proper data will be
500 	 * set for that group
501 	 */
502 	for (i = 0; i < _nscd_cfg_num_stat + 1; i++, desc++) {
503 
504 		id = (nscd_cfg_id_t *)desc;
505 
506 		if (_nscd_cfg_flag_is_set(desc->sflag,
507 		    NSCD_CFG_SFLAG_GROUP)) {
508 
509 			if (gdesc != NULL) {
510 				g_info.num_param = fn;
511 				gdesc->s_fn = fn;
512 
513 				if (g_info.num_param !=
514 				    gdesc->gi.num_param ||
515 				    !_nscd_cfg_bitmap_is_equal(
516 				    g_info.bitmap, gdesc->gi.bitmap)) {
517 
518 					_NSCD_LOG(NSCD_LOG_CONFIG,
519 					    NSCD_LOG_LEVEL_ERROR)
520 					(me, "ERROR: group (%s) "
521 					    "info mismatched: "
522 					    "group info (%d, %#6.4x) not "
523 					    "equal to the predefined one "
524 					    "(%d, %#6.4x)\n", gdesc->id.name,
525 					    g_info.num_param,
526 					    _nscd_cfg_bitmap_value(
527 					    g_info.bitmap),
528 					    gdesc->gi.num_param,
529 					    _nscd_cfg_bitmap_value(
530 					    gdesc->gi.bitmap));
531 
532 					exit(1);
533 					return (NSCD_CFG_STAT_DESC_ERROR);
534 				}
535 			}
536 
537 			gi = i;
538 			fn = 0;
539 			gdesc = desc;
540 			g_info.bitmap = NSCD_CFG_BITMAP_ZERO;
541 
542 			/*
543 			 * set the get_stat function
544 			 */
545 			gsfunc = (void *)gdesc->get_stat;
546 		} else {
547 			if (i == 0) {
548 
549 				_NSCD_LOG(NSCD_LOG_CONFIG,
550 				    NSCD_LOG_LEVEL_ERROR)
551 				(me, "ERROR: first stat "
552 				    "description is not for a group\n");
553 
554 				return (NSCD_CFG_STAT_DESC_ERROR);
555 			}
556 
557 			/*
558 			 * set bitmap: the rightmost bit represents
559 			 * the first member (index = 0) in the group,
560 			 * the next bit is for the second member
561 			 * (index = 1), and so on
562 			 */
563 			_nscd_cfg_bitmap_set_nth(g_info.bitmap, fn);
564 
565 			desc->s_fn = fn++;
566 
567 			/*
568 			 * set the get_stat function
569 			 */
570 			if (desc->get_stat == NSCD_CFG_FUNC_GET_STAT_AS_GROUP) {
571 				(void) memcpy(&desc->get_stat, &gsfunc,
572 				    sizeof (void *));
573 			}
574 		}
575 
576 		/* if end of list reached, we are done */
577 		if (i == _nscd_cfg_num_stat)
578 			break;
579 
580 		desc->g_index = gi;
581 
582 		id->index = i;
583 
584 		if ((rc = _nscd_cfg_add_index_entry(id->name,
585 		    i, type)) != NSCD_SUCCESS) {
586 
587 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
588 			(me, "unable to add index entry for stat "
589 			"description %s\n", id->name);
590 
591 			_nscd_free_db(cfg_paramDB);
592 			return (rc);
593 		} else {
594 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
595 			(me, "index entry for stat description "
596 			"%s added\n", id->name);
597 		}
598 	}
599 
600 	return (NSCD_SUCCESS);
601 }
602 
603 static nscd_rc_t
604 _nscd_cfg_copy_vlen_data(
605 	void			*data,
606 	void			**new_data_p,
607 	nscd_cfg_param_desc_t	*desc,
608 	int			*data_len,
609 	nscd_bool_t		in)
610 {
611 	int			len, dlen;
612 	nscd_cfg_vlen_data_t	*v = NULL;
613 
614 	*new_data_p = NULL;
615 	*data_len = 0;
616 
617 	/* it is OK if there is nothing to copy */
618 	if (data == NULL)
619 		return (NSCD_SUCCESS);
620 
621 	/*
622 	 * if copy to the config store we need to allocate space
623 	 * for the extra vlen header
624 	 */
625 	if (desc->type == NSCD_CFG_DATA_STRING) {
626 		len = dlen = strlen((char *)data) + 1;
627 		if (in == nscd_true)
628 			len += sizeof (nscd_cfg_vlen_data_t);
629 	} else {
630 		/*
631 		 * should not be here, since for now
632 		 * only string variable length data
633 		 * is supported
634 		 */
635 		*new_data_p = NULL;
636 		return (NSCD_CFG_PARAM_DESC_ERROR);
637 	}
638 
639 	v = calloc(1, len);
640 	if (v == NULL) {
641 		*new_data_p = NULL;
642 		return (NSCD_NO_MEMORY);
643 	}
644 
645 	/*
646 	 * if copy to the config store, set up
647 	 * the extra vlen header in which the
648 	 * pointer to, and length of, the real
649 	 * data are kept. The pointer to the real
650 	 * data, not the vlen header, is returned.
651 	 */
652 	if (in == nscd_true) {
653 		v->ptr = (char *)v + sizeof (nscd_cfg_vlen_data_t);
654 		v->len = dlen;
655 		(void) memcpy(v->ptr, data, dlen);
656 		*new_data_p = v->ptr;
657 	} else {
658 		(void) memcpy(v, data, dlen);
659 		*new_data_p = v;
660 	}
661 	*data_len = dlen;
662 
663 	return (NSCD_SUCCESS);
664 }
665 
666 static void
667 _nscd_cfg_free_vlen_data_int(
668 	void	*data)
669 {
670 	nscd_cfg_vlen_data_t	*v = NULL;
671 	void			*p;
672 
673 	if (data == NULL)
674 		return;
675 
676 	p = (char *)data - sizeof (nscd_cfg_vlen_data_t);
677 	v = (nscd_cfg_vlen_data_t *)p;
678 	if (v->ptr == data)
679 		free(v);
680 }
681 
682 static nscd_rc_t
683 _nscd_cfg_set_vlen_data_int(
684 	void		*src,
685 	void		*dest,
686 	nscd_bool_t	global)
687 {
688 	int			i, offset, dlen = 0;
689 	void			*s, *d, *new;
690 	void			*cptr;
691 	nscd_rc_t		rc;
692 	nscd_cfg_param_desc_t	*desc;
693 
694 	desc = &_nscd_cfg_param_desc[0];
695 	for (i = 0; i < _nscd_cfg_num_param; i++, desc++) {
696 
697 		if (global == nscd_true &&
698 		    _nscd_cfg_flag_is_not_set(desc->pflag,
699 		    NSCD_CFG_PFLAG_GLOBAL))
700 			continue;
701 		else if (global != nscd_true &&
702 		    _nscd_cfg_flag_is_set(desc->pflag,
703 		    NSCD_CFG_PFLAG_GLOBAL))
704 			continue;
705 
706 		if (_nscd_cfg_flag_is_set(desc->pflag,
707 		    NSCD_CFG_PFLAG_VLEN_DATA)) {
708 
709 			offset = desc->g_offset + desc->p_offset;
710 
711 			s = (char *)src + offset;
712 			cptr = *(char **)s;
713 
714 			rc = _nscd_cfg_copy_vlen_data(cptr, &new,
715 			    desc, &dlen, nscd_true);
716 			if (rc != NSCD_SUCCESS)
717 				return (rc);
718 
719 			d = (char *)dest + offset;
720 			/* free the old vlen data */
721 			if (*(char **)d == NULL)
722 				_nscd_cfg_free_vlen_data_int(*(char **)d);
723 
724 			*(char **)d = new;
725 		}
726 	}
727 
728 	return (NSCD_SUCCESS);
729 }
730 
731 static void *
732 _nscd_cfg_locate_vlen_data(
733 	void	*cfg_data,
734 	int	*len)
735 {
736 	void	*ptr, *ret;
737 
738 	ptr = *(char **)cfg_data;
739 	ret = ptr;
740 	if (ret == NULL) {
741 		*len = 0;
742 		return (NULL);
743 	}
744 	ptr = (char *)ptr - sizeof (nscd_cfg_vlen_data_t);
745 	*len = ((nscd_cfg_vlen_data_t *)ptr)->len;
746 
747 	return (ret);
748 }
749 
750 static void
751 _nscd_cfg_lock(
752 	nscd_bool_t	is_read,
753 	nscd_cfg_lock_t	*cfglock)
754 {
755 
756 	int	(*lockfunc)(rwlock_t *);
757 
758 	if (cfglock == NULL)
759 		return;
760 
761 	if (is_read == nscd_true)
762 		lockfunc = rw_rdlock;
763 	else
764 		lockfunc = rw_wrlock;
765 
766 	if (cfglock->global != NULL) {
767 
768 		(lockfunc)(cfglock->global);
769 		return;
770 	}
771 
772 	if (cfglock->alldb != NULL)
773 		(lockfunc)(cfglock->alldb);
774 
775 	if (cfglock->nswdb != NULL)
776 		(lockfunc)(cfglock->nswdb);
777 }
778 
779 static void
780 _nscd_cfg_unlock(
781 	nscd_cfg_lock_t	*cfglock)
782 {
783 	if (cfglock == NULL)
784 		return;
785 
786 	if (cfglock->global != NULL) {
787 
788 		(void) rw_unlock(cfglock->global);
789 		free(cfglock);
790 		return;
791 	}
792 
793 	if (cfglock->nswdb != NULL)
794 		(void) rw_unlock(cfglock->nswdb);
795 
796 	if (cfglock->alldb != NULL)
797 		(void) rw_unlock(cfglock->alldb);
798 
799 	free(cfglock);
800 }
801 
802 /*
803  * If vlen_data_addr is given, it will be set to the
804  * address of the pointer pointing to the vlen data.
805  * 'cfglock' will be set to point to the reader/writer
806  * lock(s) protecting the (group) configuration data.
807  */
808 static nscd_rc_t
809 _nscd_cfg_locate_cfg_data(
810 	void			**cfg_data,
811 	nscd_bool_t		is_read,
812 	nscd_cfg_param_desc_t	*desc,
813 	nscd_cfg_id_t		*nswdb,
814 	nscd_bool_t		get_group,
815 	void			**vlen_data_addr,
816 	int			*len,
817 	nscd_cfg_lock_t		**cfglock)
818 {
819 	int		offset;
820 
821 	*cfg_data = NULL;
822 	if (len != NULL)
823 		*len = 0;
824 	if (vlen_data_addr != NULL)
825 		*vlen_data_addr = NULL;
826 
827 	if (cfglock != NULL) {
828 		*cfglock = calloc(1, sizeof (nscd_cfg_lock_t));
829 		if (*cfglock == NULL)
830 			return (NSCD_NO_MEMORY);
831 	}
832 
833 	/* assume if nswdb is NULL, the param is a global one */
834 	if (nswdb == NULL) {
835 
836 		offset = desc->g_offset;
837 		if (get_group != nscd_true)
838 			offset += desc->p_offset;
839 		*cfg_data = (char *)nscd_cfg_global_current + offset;
840 
841 		if (cfglock != NULL)
842 			(*cfglock)->global = nscd_cfg_global_rwlock;
843 
844 	} else if (nswdb->index == NSCD_CFG_NSW_ALLDB_INDEX) {
845 
846 		offset = desc->g_offset;
847 		if (get_group != nscd_true)
848 			offset += desc->p_offset;
849 		*cfg_data = (char *)nscd_cfg_nsw_alldb_current +
850 		    offset;
851 
852 		if (cfglock != NULL)
853 			(*cfglock)->alldb = nscd_cfg_nsw_alldb_rwlock;
854 
855 	} else {
856 
857 		offset = nswdb->index *
858 		    (sizeof (nscd_cfg_nsw_db_data_t)) + desc->g_offset;
859 		if (get_group != nscd_true)
860 			offset += desc->p_offset;
861 		*cfg_data = (char *)nscd_cfg_nsw_db_data_current +
862 		    offset;
863 
864 		if (cfglock != NULL) {
865 			(*cfglock)->nswdb =
866 			    &nscd_cfg_nsw_db_data_rwlock[nswdb->index];
867 
868 			(*cfglock)->alldb = nscd_cfg_nsw_alldb_rwlock;
869 		}
870 	}
871 
872 	/* lock the config data */
873 	if (cfglock != NULL)
874 		_nscd_cfg_lock(is_read, *cfglock);
875 
876 	if (get_group != nscd_true &&
877 	    _nscd_cfg_flag_is_not_set(desc->pflag,
878 	    NSCD_CFG_PFLAG_GROUP) &&
879 	    (_nscd_cfg_flag_is_set(desc->pflag,
880 	    NSCD_CFG_PFLAG_VLEN_DATA))) {
881 		if (vlen_data_addr != NULL)
882 			*vlen_data_addr = *cfg_data;
883 		*cfg_data = _nscd_cfg_locate_vlen_data(*cfg_data, len);
884 		return (NSCD_SUCCESS);
885 	}
886 
887 	if (len != NULL) {
888 		if (get_group == nscd_true)
889 			*len = desc->g_size;
890 		else
891 			*len = desc->p_size;
892 	}
893 
894 	return (NSCD_SUCCESS);
895 }
896 
897 /*
898  * perform the preliminary (range) check on 'data' based on the
899  * datatype (desc->datatype) of the config parameter
900  */
901 nscd_rc_t
902 _nscd_cfg_prelim_check(
903 	nscd_cfg_param_desc_t	*desc,
904 	void			*data,
905 	nscd_cfg_error_t	**errorp)
906 {
907 
908 	char			*me = "_nscd_cfg_prelim_check";
909 	char			msg[NSCD_CFG_MAX_ERR_MSG_LEN];
910 	nscd_cfg_str_check_t	*sc;
911 	nscd_cfg_int_check_t	*ic;
912 	nscd_cfg_bitmap_check_t	*bmc;
913 	nscd_rc_t		rc = NSCD_CFG_PRELIM_CHECK_FAILED;
914 
915 	if ((nscd_cfg_str_check_t *)desc->p_check == NULL)
916 		return (NSCD_SUCCESS);
917 
918 	switch (desc->type) {
919 
920 	case NSCD_CFG_DATA_STRING:
921 
922 		sc = (nscd_cfg_str_check_t *)desc->p_check;
923 		if (sc->must_not_null == nscd_true && data == NULL) {
924 
925 			if (errorp == NULL)
926 				break;
927 
928 			(void) snprintf(msg, sizeof (msg),
929 			    gettext("data must be specified for %s"),
930 			    desc->id.name);
931 
932 			break;
933 		}
934 
935 		if (data == NULL) {
936 			rc = NSCD_SUCCESS;
937 			break;
938 		}
939 
940 		if (sc->maxlen != 0 &&
941 		    strlen((char *)data) > sc->maxlen) {
942 
943 			if (errorp == NULL)
944 				break;
945 
946 			(void) snprintf(msg, sizeof (msg),
947 			    gettext("length of data (%s) for %s larger "
948 			    "than %d"),
949 			    (char *)data, desc->id.name, sc->maxlen);
950 			break;
951 		}
952 
953 		rc = NSCD_SUCCESS;
954 
955 		break;
956 
957 	case NSCD_CFG_DATA_INTEGER:
958 
959 		ic = (nscd_cfg_int_check_t *)desc->p_check;
960 		if (*(int *)data > ic->max ||
961 		    *(int *)data < ic->min) {
962 
963 			if (errorp == NULL)
964 				break;
965 
966 			(void) snprintf(msg, sizeof (msg),
967 			    gettext("data (%d) for %s out of range "
968 			    "(%d - %d)"),
969 			    *(int *)data, desc->id.name,
970 			    ic->min, ic->max);
971 
972 			break;
973 		}
974 
975 		rc = NSCD_SUCCESS;
976 
977 		break;
978 
979 	case NSCD_CFG_DATA_BITMAP:
980 
981 		bmc = (nscd_cfg_bitmap_check_t *)desc->p_check;
982 		if (_nscd_cfg_bitmap_value(*(nscd_cfg_bitmap_t *)data) &
983 		    ~(bmc->valid_bits)) {
984 
985 			if (errorp == NULL)
986 				break;
987 
988 			(void) snprintf(msg, sizeof (msg),
989 			    gettext("data (%#6.4x) for %s contain bit "
990 			    "not in 0x%x"),
991 			    _nscd_cfg_bitmap_value(
992 			    *(nscd_cfg_bitmap_t *)data),
993 			    desc->id.name,
994 			    _nscd_cfg_bitmap_value(bmc->valid_bits));
995 			break;
996 		}
997 
998 		rc = NSCD_SUCCESS;
999 
1000 		break;
1001 	}
1002 
1003 	if (rc != NSCD_SUCCESS && errorp != NULL) {
1004 		*errorp = _nscd_cfg_make_error(rc, msg);
1005 
1006 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
1007 		(me, "invalid argument: %s\n", (*errorp)->msg);
1008 	}
1009 
1010 	return (rc);
1011 }
1012 
1013 static nscd_rc_t
1014 _nscd_cfg_notify_i(
1015 	nscd_cfg_param_desc_t	*desc,
1016 	nscd_cfg_id_t		*nswdb,
1017 	int			*skip,
1018 	nscd_cfg_error_t	**errorp)
1019 {
1020 
1021 	char			*me = "_nscd_cfg_notify_i";
1022 	int			i, num, skip_bk;
1023 	void			*cfg_data, *cdata;
1024 	void			*cookie = NULL;
1025 	nscd_rc_t		rc;
1026 	nscd_cfg_flag_t		dflag, dflag1;
1027 	nscd_cfg_bitmap_t	bitmap_c, bitmap_s, *bitmap_addr;
1028 	nscd_cfg_group_info_t	*gi;
1029 
1030 	if (errorp != NULL)
1031 		*errorp = NULL;
1032 
1033 	if (skip == NULL)
1034 		skip = &skip_bk;
1035 
1036 	*skip = 0;
1037 
1038 	if (_nscd_cfg_flag_is_not_set(desc->pflag,
1039 	    NSCD_CFG_PFLAG_GROUP)) {
1040 
1041 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1042 		(me, "ERROR: expect parameter description for group, "
1043 		    "but receive parameter description is for %s\n",
1044 		    desc->id.name);
1045 
1046 		return (NSCD_CFG_PARAM_DESC_ERROR);
1047 	}
1048 
1049 	/*
1050 	 * Set data flag going with data to be sent to the
1051 	 * verify/notify routines. Allowing the config flag
1052 	 * be exipandable, set the bits one by one.
1053 	 */
1054 	dflag = NSCD_CFG_FLAG_ZERO;
1055 	dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_STATIC_DATA);
1056 	dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_INIT);
1057 	dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_GROUP);
1058 	if (_nscd_cfg_flag_is_set(desc->pflag,
1059 	    NSCD_CFG_PFLAG_INIT_SET_ALL_DB))
1060 		dflag = _nscd_cfg_flag_set(dflag,
1061 		    NSCD_CFG_DFLAG_SET_ALL_DB);
1062 
1063 	/* get to the group data in the config store */
1064 	rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_true,
1065 	    desc, nswdb, nscd_true, NULL, NULL, NULL);
1066 	if (rc != NSCD_SUCCESS)
1067 		goto error;
1068 
1069 	/*
1070 	 * the static bitmap associated with the group
1071 	 * may be replaced before sending to the components,
1072 	 * so save the bitmap for later use
1073 	 */
1074 	gi = _nscd_cfg_get_gi(cfg_data);
1075 	bitmap_c = gi->bitmap;
1076 	bitmap_addr = &(gi->bitmap);
1077 
1078 	/*
1079 	 * the elements in this group will all be handled
1080 	 * so the caller can skip them
1081 	 */
1082 	*skip = desc->p_fn;
1083 
1084 	if (_nscd_cfg_flag_is_set(desc->pflag,
1085 	    NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP))
1086 		/* send the entire group just once */
1087 		num = 1;
1088 
1089 	else { /* send individual members one by one */
1090 
1091 		num = desc->p_fn;
1092 
1093 		/*
1094 		 * skip the first desc which is for the group
1095 		 * and get to the desc for the first member
1096 		 */
1097 		desc++;
1098 
1099 		dflag = _nscd_cfg_flag_unset(dflag,
1100 		    NSCD_CFG_DFLAG_GROUP);
1101 	}
1102 
1103 	dflag1 = dflag;
1104 	for (i = 0; i < num; i++, desc++) {
1105 
1106 		dflag = dflag1;
1107 
1108 		if (_nscd_cfg_flag_is_set(desc->pflag,
1109 		    NSCD_CFG_PFLAG_SEND_BIT_SELECTED)) {
1110 
1111 			/* set the bitmap to select just this member */
1112 			bitmap_s = NSCD_CFG_BITMAP_ZERO;
1113 			_nscd_cfg_bitmap_set_nth(bitmap_s, i);
1114 			/* replace the bitmap in the cfg data */
1115 			_nscd_cfg_bitmap_set(bitmap_addr, bitmap_s);
1116 
1117 			/*
1118 			 * send the whole group but with only one
1119 			 * member selected
1120 			 */
1121 			cdata = cfg_data;
1122 
1123 			dflag = _nscd_cfg_flag_set(dflag,
1124 			    NSCD_CFG_DFLAG_GROUP);
1125 			dflag = _nscd_cfg_flag_set(dflag,
1126 			    NSCD_CFG_DFLAG_BIT_SELECTED);
1127 		} else {
1128 			/*
1129 			 * send param data or group data:
1130 			 * param data - non-xero desc->p_offset
1131 			 * group data - zero desc->p_offset
1132 			 */
1133 			cdata = (char *)cfg_data + desc->p_offset;
1134 
1135 			/*
1136 			 * if variable length data, need to send pointer
1137 			 * to the data (not the address of the pointer)
1138 			 */
1139 			if (_nscd_cfg_flag_is_set(desc->pflag,
1140 			    NSCD_CFG_PFLAG_VLEN_DATA))
1141 				cdata = *(char **)cdata;
1142 		}
1143 
1144 		if (desc->verify != NULL) {
1145 			dflag = _nscd_cfg_flag_set(dflag,
1146 			    NSCD_CFG_DFLAG_VERIFY);
1147 			rc = desc->verify(cdata, desc, nswdb,
1148 			    dflag, errorp, &cookie);
1149 			if (rc != NSCD_SUCCESS)
1150 				goto error;
1151 		}
1152 
1153 		if (desc->notify != NULL) {
1154 			dflag = _nscd_cfg_flag_set(dflag,
1155 			    NSCD_CFG_DFLAG_NOTIFY);
1156 
1157 			rc = desc->notify(cfg_data, desc, nswdb,
1158 			    dflag, errorp, cookie);
1159 			if (rc != NSCD_SUCCESS)
1160 				goto error;
1161 		}
1162 	}
1163 
1164 	rc = NSCD_SUCCESS;
1165 
1166 	/* restore the bitmap in the cfg data */
1167 	_nscd_cfg_bitmap_set(bitmap_addr, bitmap_c);
1168 
1169 	error:
1170 
1171 	return (rc);
1172 
1173 }
1174 
1175 static nscd_rc_t
1176 _nscd_cfg_notify_init(
1177 	nscd_cfg_error_t	**errorp)
1178 {
1179 	int			i, j, skip;
1180 	nscd_rc_t		rc;
1181 	nscd_cfg_id_t		*nswdb = NULL;
1182 	nscd_cfg_param_desc_t	*desc;
1183 
1184 	if (errorp != NULL)
1185 		*errorp = NULL;
1186 
1187 	for (i = 0; i < _nscd_cfg_num_param; i++) {
1188 
1189 		desc = &_nscd_cfg_param_desc[i];
1190 
1191 		if (_nscd_cfg_flag_is_set(desc->pflag,
1192 		    NSCD_CFG_PFLAG_GLOBAL)) { /* global cfg data */
1193 
1194 			rc = _nscd_cfg_notify_i(desc, NULL, &skip, errorp);
1195 		} else {
1196 
1197 			/*
1198 			 * if use defaults for all nsswitch database,
1199 			 * send the config data to verify/notify once
1200 			 */
1201 			if (_nscd_cfg_flag_is_set(desc->pflag,
1202 			    NSCD_CFG_PFLAG_INIT_SET_ALL_DB)) {
1203 
1204 				nswdb = &_nscd_cfg_nsw_alldb;
1205 
1206 				rc = _nscd_cfg_notify_i(desc, nswdb,
1207 				    &skip, errorp);
1208 			} else { /* send data once for each nsw db */
1209 
1210 				for (j = 0; j < _nscd_cfg_num_nsw_db; j++) {
1211 
1212 					nswdb = &_nscd_cfg_nsw_db[j];
1213 
1214 					rc = _nscd_cfg_notify_i(desc,
1215 					    nswdb, &skip, errorp);
1216 
1217 					if (rc != NSCD_SUCCESS)
1218 						break;
1219 				}
1220 			}
1221 		}
1222 
1223 		if (rc != NSCD_SUCCESS)
1224 			return (rc);
1225 
1226 		i += skip;
1227 	}
1228 
1229 	return (NSCD_SUCCESS);
1230 }
1231 
1232 nscd_rc_t
1233 _nscd_cfg_init(
1234 	nscd_cfg_error_t		**errorp)
1235 {
1236 
1237 	int				i, j, datalen;
1238 	int				dbi = 0, dbj = 0;
1239 	char				*dest, *src;
1240 	char				*dbni = NULL, *dbnj = NULL;
1241 	nscd_rc_t			rc;
1242 	nscd_cfg_nsw_spc_default_t	*spc;
1243 
1244 	if (errorp != NULL)
1245 		*errorp = NULL;
1246 
1247 	rc = _nscd_cfg_init_param();
1248 	if (rc != NSCD_SUCCESS)
1249 		return (rc);
1250 
1251 	rc = _nscd_cfg_init_stat();
1252 	if (rc != NSCD_SUCCESS)
1253 		return (rc);
1254 
1255 	nscd_cfg_global_current = calloc(1,
1256 	    sizeof (nscd_cfg_global_data_t));
1257 	if (nscd_cfg_global_current == NULL)
1258 		return (NSCD_NO_MEMORY);
1259 
1260 	nscd_cfg_nsw_alldb_current = calloc(1,
1261 	    sizeof (nscd_cfg_nsw_db_data_t));
1262 	if (nscd_cfg_nsw_alldb_current == NULL)
1263 		return (NSCD_NO_MEMORY);
1264 
1265 	nscd_cfg_nsw_db_data_current = calloc(_nscd_cfg_num_nsw_db,
1266 	    sizeof (nscd_cfg_nsw_db_data_t));
1267 	if (nscd_cfg_nsw_db_data_current == NULL)
1268 		return (NSCD_NO_MEMORY);
1269 
1270 	nscd_cfg_global_rwlock = calloc(1, sizeof (rwlock_t));
1271 	if (nscd_cfg_global_rwlock == NULL)
1272 		return (NSCD_NO_MEMORY);
1273 	(void) rwlock_init(nscd_cfg_global_rwlock, NULL, NULL);
1274 
1275 	*nscd_cfg_global_current = nscd_cfg_global_default;
1276 
1277 	rc = _nscd_cfg_set_vlen_data_int(&nscd_cfg_global_default,
1278 	    nscd_cfg_global_current, nscd_true);
1279 	if (rc != NSCD_SUCCESS)
1280 		return (rc);
1281 
1282 	nscd_cfg_nsw_db_data_rwlock = calloc(_nscd_cfg_num_nsw_db,
1283 	    sizeof (rwlock_t));
1284 	if (nscd_cfg_nsw_db_data_rwlock == NULL)
1285 		return (NSCD_NO_MEMORY);
1286 
1287 	/* set per switch db config to the default for all db's */
1288 	for (i = 0; i < _nscd_cfg_num_nsw_db; i++) {
1289 
1290 		nscd_cfg_nsw_db_data_current[i] =
1291 		    nscd_cfg_nsw_db_data_default;
1292 
1293 		(void) rwlock_init(&nscd_cfg_nsw_db_data_rwlock[i],
1294 		    NULL, NULL);
1295 	}
1296 
1297 	/* add db specific defaults */
1298 	for (i = 0; i < _nscd_cfg_num_nsw_default; i++) {
1299 
1300 		if (_nscd_cfg_nsw_spc_default[i].data == NULL)
1301 			continue;
1302 
1303 		if (_nscd_cfg_nsw_spc_default[i].db != dbni) {
1304 			for (j = 0; j < _nscd_cfg_num_nsw_db; j++) {
1305 
1306 				if (strcmp(_nscd_cfg_nsw_db[j].name,
1307 				    _nscd_cfg_nsw_spc_default[i].db) != 0)
1308 					continue;
1309 
1310 				dbi = _nscd_cfg_nsw_db[j].index;
1311 				dbni = _nscd_cfg_nsw_db[j].name;
1312 				break;
1313 			}
1314 		}
1315 
1316 		dest = (char *)&nscd_cfg_nsw_db_data_current[dbi] +
1317 		    _nscd_cfg_nsw_spc_default[i].group_off +
1318 		    _nscd_cfg_nsw_spc_default[i].param_off;
1319 
1320 		src = _nscd_cfg_nsw_spc_default[i].data;
1321 		datalen = _nscd_cfg_nsw_spc_default[i].data_len;
1322 
1323 		(void) memcpy(dest, src, datalen);
1324 	}
1325 
1326 	/* add db specific defaults via links */
1327 	for (i = 0; i < _nscd_cfg_num_link_default; i++) {
1328 
1329 		if (_nscd_cfg_nsw_link_default[i].data == NULL)
1330 			continue;
1331 
1332 		spc = _nscd_cfg_nsw_link_default[i].data;
1333 
1334 		if (_nscd_cfg_nsw_link_default[i].db != dbni) {
1335 			for (j = 0; j < _nscd_cfg_num_nsw_db; j++) {
1336 
1337 				if (strcmp(_nscd_cfg_nsw_db[j].name,
1338 				    _nscd_cfg_nsw_link_default[i].db) != 0)
1339 					continue;
1340 
1341 				dbi = _nscd_cfg_nsw_db[j].index;
1342 				dbni = _nscd_cfg_nsw_db[j].name;
1343 				break;
1344 			}
1345 		}
1346 
1347 		dest = (char *)&nscd_cfg_nsw_db_data_current[dbi] +
1348 		    _nscd_cfg_nsw_link_default[i].group_off +
1349 		    _nscd_cfg_nsw_link_default[i].param_off;
1350 
1351 		if (_nscd_cfg_nsw_db[j].name != dbnj) {
1352 			for (j = 0; j < _nscd_cfg_num_nsw_db; j++) {
1353 
1354 				if (strcmp(spc->db,
1355 				    _nscd_cfg_nsw_db[j].name) != 0)
1356 					continue;
1357 
1358 				dbnj = _nscd_cfg_nsw_db[j].name;
1359 				dbj = _nscd_cfg_nsw_db[j].index;
1360 				break;
1361 			}
1362 		}
1363 
1364 		src = (char *)&nscd_cfg_nsw_db_data_current[dbj] +
1365 		    spc->group_off + spc->param_off;
1366 		datalen = spc->data_len;
1367 
1368 		(void) memcpy(dest, src, datalen);
1369 	}
1370 
1371 	/* fix up variable length fields */
1372 	for (i = 0; i < _nscd_cfg_num_nsw_db; i++) {
1373 
1374 		rc = _nscd_cfg_set_vlen_data_int(
1375 		    &nscd_cfg_nsw_db_data_current[i],
1376 		    &nscd_cfg_nsw_db_data_current[i], nscd_false);
1377 		if (rc != NSCD_SUCCESS)
1378 			return (rc);
1379 	}
1380 
1381 	nscd_cfg_nsw_alldb_rwlock = calloc(1, sizeof (rwlock_t));
1382 	if (nscd_cfg_nsw_alldb_rwlock == NULL)
1383 		return (NSCD_NO_MEMORY);
1384 
1385 	(void) rwlock_init(nscd_cfg_nsw_alldb_rwlock, NULL, NULL);
1386 
1387 	rc = _nscd_cfg_set_vlen_data_int(
1388 	    &nscd_cfg_nsw_db_data_default,
1389 	    nscd_cfg_nsw_alldb_current, nscd_false);
1390 	if (rc != NSCD_SUCCESS)
1391 		return (rc);
1392 
1393 	/*
1394 	 * notify and send the configuration data to
1395 	 * the nscd components
1396 	 */
1397 	rc = _nscd_cfg_notify_init(errorp);
1398 	if (rc != NSCD_SUCCESS)
1399 		return (rc);
1400 
1401 	return (NSCD_SUCCESS);
1402 }
1403 
1404 static nscd_rc_t
1405 _nscd_cfg_get_handle_common(
1406 	nscd_cfg_list_type_t	type,
1407 	char			*name,
1408 	char			*nswdb_name,
1409 	nscd_cfg_handle_t	**handle,
1410 	nscd_cfg_error_t	**errorp)
1411 {
1412 
1413 	int			i, is_global;
1414 	char			*desc_str;
1415 	nscd_cfg_handle_t	*h;
1416 	nscd_cfg_param_desc_t	*pdesc;
1417 	nscd_cfg_stat_desc_t	*sdesc;
1418 	char			*me = "_nscd_cfg_get_handle_common";
1419 	char			msg[NSCD_CFG_MAX_ERR_MSG_LEN];
1420 	nscd_rc_t		rc = NSCD_INVALID_ARGUMENT;
1421 
1422 	if (handle == NULL) {
1423 
1424 		(void) snprintf(msg, sizeof (msg),
1425 		    gettext("address of handle not specified"));
1426 		if (errorp)
1427 			*errorp = _nscd_cfg_make_error(rc, msg);
1428 
1429 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
1430 		(me, "invalid argument: %s\n", msg);
1431 
1432 		return (rc);
1433 	}
1434 
1435 	*handle = NULL;
1436 
1437 	if (name == NULL) {
1438 
1439 		(void) snprintf(msg, sizeof (msg),
1440 		    gettext("name not specified"));
1441 		if (errorp)
1442 			*errorp = _nscd_cfg_make_error(rc, msg);
1443 
1444 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
1445 		(me, "invalid argument: %s\n");
1446 
1447 		return (rc);
1448 	}
1449 
1450 	h = calloc(1, sizeof (nscd_cfg_handle_t));
1451 	if (h == NULL)
1452 		return (NSCD_NO_MEMORY);
1453 	h->type = type;
1454 
1455 	if (type == NSCD_CFG_LIST_PARAM)
1456 		desc_str = gettext("configuration parameter");
1457 	else
1458 		desc_str = gettext("statistics");
1459 
1460 	/* get param or stat descriptor */
1461 	i = _nscd_cfg_get_index(name, type);
1462 	if (i != -1) {
1463 
1464 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
1465 		(me, "%s: index of %s is %d\n", desc_str, name, i);
1466 
1467 		if (type == NSCD_CFG_LIST_PARAM) {
1468 			pdesc = &_nscd_cfg_param_desc[i];
1469 			(void) memcpy(&h->desc, &pdesc, sizeof (pdesc));
1470 			is_global = _nscd_cfg_flag_is_set(
1471 			    pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL);
1472 
1473 			/* hidden params are not exposed */
1474 			if (_nscd_cfg_flag_is_set(
1475 			    pdesc->pflag, NSCD_CFG_PFLAG_HIDDEN))
1476 				i = -1;
1477 
1478 			if (_nscd_cfg_flag_is_set(pdesc->pflag,
1479 			    NSCD_CFG_PFLAG_OBSOLETE)) {
1480 				_NSCD_LOG(NSCD_LOG_CONFIG,
1481 				    NSCD_LOG_LEVEL_WARNING)
1482 				(me, gettext("%s: %s is obsolete and "
1483 				    "will be ignored\n"),
1484 				    desc_str, name);
1485 			}
1486 		} else {
1487 			sdesc = &_nscd_cfg_stat_desc[i];
1488 			(void) memcpy(&h->desc, &sdesc, sizeof (sdesc));
1489 			is_global = _nscd_cfg_flag_is_set(
1490 			    sdesc->sflag, NSCD_CFG_SFLAG_GLOBAL);
1491 		}
1492 	}
1493 
1494 	if (i == -1) {
1495 
1496 		(void) snprintf(msg, sizeof (msg),
1497 		    gettext("%s: unknown name \"%s\""), desc_str, name);
1498 		if (errorp)
1499 			*errorp = _nscd_cfg_make_error(rc, msg);
1500 
1501 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1502 		(me, "%s\n", msg);
1503 
1504 		free(h);
1505 		return (rc);
1506 	}
1507 
1508 	/*
1509 	 * if the param/stat is not a global one, we need to
1510 	 * know which nsswitch database we are dealing with
1511 	 */
1512 	if (is_global == 0) {
1513 		if (nswdb_name == NULL) {
1514 
1515 			(void) snprintf(msg, sizeof (msg),
1516 			gettext("%s: switch database name not specified"),
1517 			    desc_str);
1518 			if (errorp)
1519 				*errorp = _nscd_cfg_make_error(rc, msg);
1520 
1521 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1522 			(me, "%s for non-global param or stat %s\n",
1523 			    msg, name);
1524 
1525 			free(h);
1526 			return (rc);
1527 		}
1528 	} else {
1529 
1530 		if (nswdb_name != NULL) {
1531 
1532 			(void) snprintf(msg, sizeof (msg),
1533 			    gettext("%s: switch database specified for "
1534 			    "global data"), desc_str);
1535 			if (errorp)
1536 				*errorp = _nscd_cfg_make_error(rc, msg);
1537 
1538 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1539 			(me, "%s %s\n", msg, name);
1540 
1541 			free(h);
1542 			return (rc);
1543 		}
1544 
1545 		*handle = h;
1546 		return (NSCD_SUCCESS);
1547 	}
1548 
1549 	/* get nsw DB id */
1550 	i = _nscd_cfg_get_index(nswdb_name, NSCD_CFG_LIST_NSW_DB);
1551 	if (i != -1) {
1552 
1553 		if (i == NSCD_CFG_NSW_ALLDB_INDEX)
1554 			h->nswdb = &_nscd_cfg_nsw_alldb;
1555 		else
1556 			h->nswdb = &_nscd_cfg_nsw_db[i];
1557 
1558 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
1559 		(me, "%s: index of %s is %d\n",
1560 		    desc_str, nswdb_name, i);
1561 	} else {
1562 
1563 		(void) snprintf(msg, sizeof (msg),
1564 		    gettext("%s: unknown switch database name \"%s\""),
1565 		    desc_str, nswdb_name);
1566 		if (errorp)
1567 			*errorp = _nscd_cfg_make_error(rc, msg);
1568 
1569 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1570 		(me, "%s\n", msg);
1571 
1572 		free(h);
1573 		return (NSCD_CFG_UNSUPPORTED_SWITCH_DB);
1574 	}
1575 
1576 	*handle = h;
1577 
1578 	return (NSCD_SUCCESS);
1579 }
1580 
1581 nscd_rc_t
1582 _nscd_cfg_get_handle(
1583 	char			*param_name,
1584 	char			*nswdb_name,
1585 	nscd_cfg_handle_t	**handle,
1586 	nscd_cfg_error_t	**errorp)
1587 {
1588 
1589 	return (_nscd_cfg_get_handle_common(NSCD_CFG_LIST_PARAM,
1590 	    param_name, nswdb_name, handle, errorp));
1591 }
1592 
1593 nscd_rc_t
1594 _nscd_cfg_get_stat_handle(
1595 	char			*stat_name,
1596 	char			*nswdb_name,
1597 	nscd_cfg_handle_t	**handle,
1598 	nscd_cfg_error_t	**errorp)
1599 {
1600 
1601 	return (_nscd_cfg_get_handle_common(NSCD_CFG_LIST_STAT,
1602 	    stat_name, nswdb_name, handle, errorp));
1603 }
1604 
1605 void
1606 _nscd_cfg_free_handle(
1607 	nscd_cfg_handle_t	*handle)
1608 {
1609 
1610 	free(handle);
1611 
1612 }
1613 
1614 static void
1615 _nscd_cfg_free_vlen_data_group(
1616 	nscd_cfg_param_desc_t	*gdesc,
1617 	void			*group_data,
1618 	nscd_bool_t		in)
1619 {
1620 	int			num;
1621 	void			*dest, *ptr;
1622 	nscd_cfg_param_desc_t	*desc;
1623 
1624 	desc = gdesc;
1625 
1626 	num = ((nscd_cfg_group_info_t *)group_data)->num_param;
1627 
1628 	while (num-- > 0) {
1629 
1630 		desc++;
1631 
1632 		/* skip fixed length data */
1633 		if (_nscd_cfg_flag_is_not_set(desc->pflag,
1634 		    NSCD_CFG_PFLAG_VLEN_DATA))
1635 			continue;
1636 
1637 		dest = (char *)group_data + desc->p_offset;
1638 		ptr = *(char **)dest;
1639 		if (ptr == NULL)
1640 			continue;
1641 		if (in == nscd_true)
1642 			_nscd_cfg_free_vlen_data_int(ptr);
1643 		else
1644 			free(ptr);
1645 	}
1646 }
1647 
1648 void
1649 _nscd_cfg_free_param_data(
1650 	void			*data)
1651 {
1652 
1653 	if (data == NULL)
1654 		return;
1655 
1656 	free(data);
1657 }
1658 
1659 void
1660 _nscd_cfg_free_group_data(
1661 	nscd_cfg_handle_t	*handle,
1662 	void			*data)
1663 {
1664 
1665 	nscd_cfg_param_desc_t	*desc;
1666 	nscd_cfg_group_info_t	*gi;
1667 
1668 	if (handle == NULL || data == NULL)
1669 		return;
1670 
1671 	desc = _nscd_cfg_get_desc(handle);
1672 	gi = (nscd_cfg_group_info_t *)data;
1673 	if (desc->p_fn != gi->num_param)
1674 		return;
1675 
1676 	_nscd_cfg_free_vlen_data_group(desc, data, nscd_false);
1677 
1678 	free(data);
1679 }
1680 
1681 void
1682 _nscd_cfg_free_error(
1683 	nscd_cfg_error_t	*error)
1684 {
1685 
1686 	if (error == NULL)
1687 		return;
1688 
1689 	free(error);
1690 }
1691 
1692 static nscd_rc_t
1693 _nscd_cfg_copy_param_data(
1694 	nscd_cfg_param_desc_t	*desc,
1695 	void			*dest,
1696 	void			*pdata,
1697 	nscd_bool_t		in,
1698 	nscd_bool_t		set_addr)
1699 {
1700 
1701 	char			*me = "_nscd_cfg_copy_param_data";
1702 	void			*tmp;
1703 	int			dlen;
1704 	nscd_rc_t		rc = NSCD_SUCCESS;
1705 
1706 	if (desc == NULL || dest == NULL) {
1707 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1708 		(me, "input desc == %p, dest == %p\n", desc, dest);
1709 		return (NSCD_INVALID_ARGUMENT);
1710 	}
1711 
1712 	/* fixed length data */
1713 	if (_nscd_cfg_flag_is_not_set(desc->pflag,
1714 	    NSCD_CFG_PFLAG_VLEN_DATA)) {
1715 		(void) memcpy(dest, pdata, desc->p_size);
1716 		goto done;
1717 	}
1718 
1719 
1720 	/* variable length data from this point on */
1721 
1722 	/* make a copy of the variable length data */
1723 	rc = _nscd_cfg_copy_vlen_data(pdata, &tmp, desc, &dlen, in);
1724 	if (rc != NSCD_SUCCESS)
1725 		goto done;
1726 
1727 	if (in == nscd_true) { /* data to internal */
1728 
1729 		/* free the variable length data in the config store */
1730 		if (*(char **)dest != NULL)
1731 			_nscd_cfg_free_vlen_data_int(*(char **)dest);
1732 	}
1733 
1734 	if (set_addr == nscd_true) {
1735 		/*
1736 		 * set the addr of the vlen data
1737 		 */
1738 		*(char **)dest = tmp;
1739 	} else {
1740 		/*
1741 		 * copy the data content (not address)
1742 		 */
1743 		(void) memcpy(dest, tmp, dlen);
1744 	}
1745 
1746 	done:
1747 
1748 	return (rc);
1749 }
1750 
1751 static nscd_rc_t
1752 _nscd_cfg_copy_group_data_in(
1753 	nscd_cfg_param_desc_t	*gdesc,
1754 	nscd_cfg_group_info_t	*gi,
1755 	void			*group_dest,
1756 	void			*group_src)
1757 {
1758 	int			i, num;
1759 	nscd_cfg_param_desc_t	*desc;
1760 	void			*src, *dest;
1761 
1762 	i = 0;
1763 	num = gi->num_param;
1764 	desc = gdesc;
1765 
1766 	while (num-- > 0) {
1767 
1768 		desc++;
1769 
1770 		/* if member not selected by bitmap, skip */
1771 		if (_nscd_cfg_bitmap_is_not_set(gi->bitmap, i++))
1772 			continue;
1773 
1774 		src = (char *)group_src + desc->p_offset;
1775 		dest = (char *)group_dest + desc->p_offset;
1776 
1777 		/*
1778 		 * if variable length data, free and replace the old
1779 		 * with the new
1780 		 */
1781 		if (_nscd_cfg_flag_is_set(desc->pflag,
1782 		    NSCD_CFG_PFLAG_VLEN_DATA)) {
1783 			_nscd_cfg_free_vlen_data_int(*(char **)dest);
1784 			*(char **)dest = *(char **)src;
1785 			*(char **)src = NULL;
1786 		} else {
1787 			/*
1788 			 * fixed length data, just copy it
1789 			 */
1790 			(void) memcpy(dest, src, desc->p_size);
1791 		}
1792 	}
1793 
1794 	return (NSCD_SUCCESS);
1795 }
1796 
1797 static nscd_rc_t
1798 _nscd_cfg_copy_group_data_out(
1799 	nscd_cfg_param_desc_t	*gdesc,
1800 	void			*group_dest,
1801 	void			*group_src)
1802 {
1803 
1804 	char			*me = "_nscd_cfg_copy_group_data_out";
1805 	void			*src, *dest;
1806 	int			dlen;
1807 	int			num;
1808 	nscd_cfg_group_info_t	*gi;
1809 	nscd_rc_t		rc = NSCD_SUCCESS;
1810 	nscd_cfg_param_desc_t	*desc;
1811 
1812 	if (group_dest == NULL) {
1813 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1814 		(me, "input group_dest = NULL\n");
1815 		return (NSCD_INVALID_ARGUMENT);
1816 	}
1817 
1818 	gi = _nscd_cfg_get_gi(group_src);
1819 	num = gi->num_param;
1820 	desc = gdesc;
1821 
1822 	while (num-- > 0) {
1823 
1824 		desc++;
1825 
1826 		dest = (char *)group_dest + desc->p_offset;
1827 		src = (char *)group_src + desc->p_offset;
1828 
1829 		/*
1830 		 * if variable length data, get the real
1831 		 * address and length of the data
1832 		 */
1833 		if (_nscd_cfg_flag_is_set(desc->pflag,
1834 		    NSCD_CFG_PFLAG_VLEN_DATA)) {
1835 			src = _nscd_cfg_locate_vlen_data(src, &dlen);
1836 			if (dlen == NULL)
1837 				continue;
1838 		}
1839 
1840 		/*
1841 		 * The nscd_true asks _nscd_cfg_copy_param_data
1842 		 * to set addr of the vlen data in 'dest' rather
1843 		 * than copying the data content
1844 		 */
1845 		rc = _nscd_cfg_copy_param_data(desc, dest, src,
1846 		    nscd_false, nscd_true);
1847 		if (rc != NSCD_SUCCESS) {
1848 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1849 			(me, "unable to copy param data for %s\n",
1850 			    desc->id.name);
1851 
1852 			_nscd_cfg_free_vlen_data_group(gdesc,
1853 			    group_dest, nscd_false);
1854 
1855 			free(group_dest);
1856 
1857 			return (rc);
1858 		}
1859 	}
1860 
1861 	/*
1862 	 * set group bitmap
1863 	 */
1864 	(void) memcpy(group_dest, group_src,
1865 	    sizeof (nscd_cfg_group_info_t));
1866 
1867 	return (rc);
1868 }
1869 
1870 
1871 /*
1872  * group_cfg is needed always; group_src may be NULL if
1873  * param_index not zero and pdata not NULL; group_cfg and
1874  * pdata should not be both non-NULL
1875  */
1876 static nscd_rc_t
1877 _nscd_cfg_copy_group_data_merge(
1878 	nscd_cfg_param_desc_t	*gdesc,
1879 	void			**group_dest,
1880 	void			*group_src,
1881 	void			*group_cfg,
1882 	int			param_index,
1883 	void			*pdata)
1884 {
1885 
1886 	char			*me = "_nscd_cfg_copy_group_data_merge";
1887 	void			*src, *dest, *tmp_dest = NULL;
1888 	int			num, i = 0;
1889 	nscd_cfg_group_info_t	*gi;
1890 	nscd_rc_t		rc = NSCD_SUCCESS;
1891 	nscd_cfg_param_desc_t	*desc;
1892 	nscd_cfg_bitmap_t	bitmap;
1893 
1894 	if (group_dest == NULL) {
1895 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1896 		(me, "input **group_dest == NULL\n");
1897 		return (NSCD_INVALID_ARGUMENT);
1898 	}
1899 
1900 	if (group_cfg == NULL) {
1901 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1902 		(me, "input **group_cfg == NULL\n");
1903 		return (NSCD_INVALID_ARGUMENT);
1904 	}
1905 
1906 	if (param_index != NULL && pdata == NULL) {
1907 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1908 		(me, "param_index != NULL but pdata == %p\n", pdata);
1909 		return (NSCD_INVALID_ARGUMENT);
1910 	}
1911 
1912 	tmp_dest = calloc(1, gdesc->g_size);
1913 	if (tmp_dest == NULL)
1914 		return (NSCD_NO_MEMORY);
1915 
1916 	if (group_src != NULL)
1917 		gi = _nscd_cfg_get_gi(group_src);
1918 	else {
1919 		gi = _nscd_cfg_get_gi(group_cfg);
1920 		bitmap = NSCD_CFG_BITMAP_ZERO;
1921 	}
1922 
1923 	num = gi->num_param;
1924 	desc = gdesc;
1925 
1926 	while (num-- > 0) {
1927 
1928 		desc++;
1929 
1930 		dest = (char *)tmp_dest + desc->p_offset;
1931 
1932 		/*
1933 		 * if member not selected by bitmap in group_src,
1934 		 * get the member data in group_cfg
1935 		 */
1936 		if (_nscd_cfg_bitmap_is_not_set(gi->bitmap, i++) ||
1937 		    group_src == NULL) {
1938 			src = (char *)group_cfg + desc->p_offset;
1939 		} else
1940 			src = (char *)group_src + desc->p_offset;
1941 
1942 		if (desc->id.index == param_index) {
1943 
1944 			/* use the param data in pdata if provided */
1945 			src = pdata;
1946 			_nscd_cfg_bitmap_set_nth(bitmap, i);
1947 		}
1948 
1949 		/*
1950 		 * if variable length data, get to the data
1951 		 * instead of pointer to the data
1952 		 */
1953 		if (_nscd_cfg_flag_is_set(desc->pflag,
1954 		    NSCD_CFG_PFLAG_VLEN_DATA))
1955 			src = *(char **)src;
1956 
1957 		/*
1958 		 * nscd_true asks _nscd_cfg_copy_param_data to
1959 		 * set addr of the vlen data in 'dest' rather
1960 		 * than copying the data content
1961 		 */
1962 		rc = _nscd_cfg_copy_param_data(desc, dest, src,
1963 		    nscd_true, nscd_true);
1964 		if (rc != NSCD_SUCCESS) {
1965 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1966 			(me, "unable to copy param data for %s\n",
1967 			    desc->id.name);
1968 
1969 			_nscd_cfg_free_vlen_data_group(gdesc,
1970 			    tmp_dest, nscd_true);
1971 
1972 			free(tmp_dest);
1973 
1974 			return (rc);
1975 		}
1976 	}
1977 
1978 	*group_dest = tmp_dest;
1979 
1980 	/*
1981 	 * set bitmap: if input is group data, use the one
1982 	 * given; if input is param data, use the one computed
1983 	 * above
1984 	 */
1985 	if (group_src != NULL)
1986 		(void) memcpy(*group_dest, group_src,
1987 		    sizeof (nscd_cfg_group_info_t));
1988 	else {
1989 		gi = _nscd_cfg_get_gi(*group_dest);
1990 		_nscd_cfg_bitmap_set(&gi->bitmap, bitmap);
1991 	}
1992 
1993 	return (rc);
1994 }
1995 
1996 /* ARGSUSED */
1997 nscd_rc_t
1998 _nscd_cfg_get(
1999 	nscd_cfg_handle_t	*handle,
2000 	void			**data,
2001 	int			*data_len,
2002 	nscd_cfg_error_t	**errorp)
2003 {
2004 	char			*me = "_nscd_cfg_get";
2005 	int			dlen;
2006 	nscd_rc_t		rc = NSCD_SUCCESS;
2007 	nscd_cfg_id_t		*nswdb;
2008 	nscd_cfg_param_desc_t	*desc;
2009 	void			*cfg_data, *ptr = NULL;
2010 	nscd_bool_t		get_group = nscd_false;
2011 	nscd_bool_t		out = nscd_false;
2012 	nscd_cfg_lock_t		*lock = NULL;
2013 
2014 	if (data_len != NULL)
2015 		*data_len = 0;
2016 
2017 	if (data == NULL) {
2018 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2019 		(me, "input data = %p\n", data);
2020 		return (NSCD_INVALID_ARGUMENT);
2021 	}
2022 
2023 	*data = NULL;
2024 
2025 	if (handle == NULL) {
2026 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2027 		(me, "handle is NULL\n");
2028 		return (NSCD_INVALID_ARGUMENT);
2029 	}
2030 
2031 	nswdb = handle->nswdb;
2032 	desc = (nscd_cfg_param_desc_t *)handle->desc;
2033 
2034 	if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP))
2035 		get_group = nscd_true;
2036 
2037 	/*
2038 	 * locate the current value of the param or group
2039 	 * and lock the config data for reading
2040 	 */
2041 	rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_true, desc,
2042 	    nswdb, get_group, NULL, &dlen, &lock);
2043 	if (rc != NSCD_SUCCESS) {
2044 
2045 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2046 		(me, "unable to locate config data\n");
2047 		return (rc);
2048 
2049 	} else if (cfg_data == NULL) /* NULL vlen data */
2050 		goto done;
2051 
2052 	ptr = calloc(1, dlen);
2053 	if (ptr == NULL) {
2054 		rc = NSCD_NO_MEMORY;
2055 		goto error_exit;
2056 	}
2057 
2058 	if (get_group == nscd_true) {
2059 
2060 		rc = _nscd_cfg_copy_group_data_out(desc, ptr, cfg_data);
2061 		if (rc != NSCD_SUCCESS) {
2062 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2063 			(me, "unable to copy group data %p: "
2064 			"error = %d\n", cfg_data, rc);
2065 
2066 			goto error_exit;
2067 		}
2068 	} else {
2069 		/*
2070 		 * nscd_false asks _nscd_cfg_copy_param_data to
2071 		 * copy the data content rather than just setting
2072 		 * the addr of the vlen data in 'ptr'
2073 		 */
2074 		rc = _nscd_cfg_copy_param_data(desc, ptr, cfg_data,
2075 		    out, nscd_false);
2076 
2077 		if (rc != NSCD_SUCCESS) {
2078 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2079 			(me, "unable to copy param data %p: "
2080 			"error = %d\n", cfg_data, rc);
2081 
2082 			goto error_exit;
2083 		}
2084 	}
2085 
2086 	*data = ptr;
2087 
2088 	done:
2089 
2090 	if (data_len != NULL)
2091 		*data_len = dlen;
2092 
2093 	_nscd_cfg_unlock(lock);
2094 
2095 	return (NSCD_SUCCESS);
2096 
2097 	error_exit:
2098 
2099 	_nscd_cfg_unlock(lock);
2100 	if (ptr != NULL)
2101 		free(ptr);
2102 
2103 	return (rc);
2104 }
2105 
2106 /*
2107  * three type of data:
2108  * 1 - single param
2109  * 	desc is that of the param
2110  * 2 - single param to be sent in a group
2111  *	a single bit is set in the bitmap,
2112  * 	desc is that of the group
2113  * 3 - group data
2114  *	one of more bits are set in the bitmap,
2115  * 	desc is that of the group
2116  */
2117 static nscd_rc_t
2118 _nscd_cfg_notify_s(
2119 	nscd_cfg_param_desc_t	*desc,
2120 	nscd_cfg_id_t		*nswdb,
2121 	void			*data,
2122 	nscd_cfg_error_t	**errorp)
2123 {
2124 	int			i, num, is_group = 0;
2125 	void			*cookie = NULL;
2126 	void			*cdata;
2127 	nscd_rc_t		rc;
2128 	nscd_cfg_flag_t		dflag, dflag1;
2129 	nscd_cfg_bitmap_t	bitmap_s, bitmap_in, *bitmap_addr = NULL;
2130 	nscd_cfg_group_info_t	*gi;
2131 
2132 	if (errorp != NULL)
2133 		*errorp = NULL;
2134 
2135 	/*
2136 	 * Set data flag going with data to be sent to the
2137 	 * verify/notify routines. To allow the config flag
2138 	 * be exipandable, set the bits one by one.
2139 	 */
2140 	dflag = NSCD_CFG_FLAG_ZERO;
2141 	dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_STATIC_DATA);
2142 	if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) {
2143 		dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_GROUP);
2144 		is_group = 1;
2145 	}
2146 	if (nswdb != NULL &&
2147 	    strcmp(NSCD_CFG_NSW_ALLDB, nswdb->name) == 0)
2148 		dflag = _nscd_cfg_flag_set(dflag,
2149 		    NSCD_CFG_DFLAG_SET_ALL_DB);
2150 
2151 	/*
2152 	 * the bitmap in the input data may be replaced before
2153 	 * sending to the components, so save the bitmap for
2154 	 * later use
2155 	 */
2156 	if (is_group == 1) {
2157 		gi = _nscd_cfg_get_gi(data);
2158 		bitmap_in = gi->bitmap;
2159 		bitmap_addr = &(gi->bitmap);
2160 
2161 		if (_nscd_cfg_flag_is_set(desc->pflag,
2162 		    NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP))
2163 			/* send the entire group just once */
2164 			num = 1;
2165 
2166 		else { /* send individual members one by one */
2167 
2168 			num = desc->p_fn;
2169 
2170 			/*
2171 			 * skip the first desc which is for the group
2172 			 * and get to the desc for the first member
2173 			 */
2174 			desc++;
2175 
2176 			dflag = _nscd_cfg_flag_unset(dflag,
2177 			    NSCD_CFG_DFLAG_GROUP);
2178 		}
2179 	} else {
2180 		/* not group data, send the member once */
2181 			num = 1;
2182 	}
2183 
2184 	dflag1 = dflag;
2185 	for (i = 0; i < num; i++, desc++) {
2186 
2187 		dflag = dflag1;
2188 
2189 		if (is_group == 0) {
2190 			cdata = data;
2191 			goto verify_data;
2192 		}
2193 
2194 		if (_nscd_cfg_flag_is_set(desc->pflag,
2195 		    NSCD_CFG_PFLAG_SEND_BIT_SELECTED)) {
2196 
2197 			/* set the bitmap to select just this member */
2198 			bitmap_s = NSCD_CFG_BITMAP_ZERO;
2199 			_nscd_cfg_bitmap_set_nth(bitmap_s, i);
2200 			/* replace the bitmap in the input data */
2201 			_nscd_cfg_bitmap_set(bitmap_addr, bitmap_s);
2202 
2203 			/*
2204 			 * send the whole group but with only one
2205 			 * member selected
2206 			 */
2207 			cdata = data;
2208 
2209 			dflag = _nscd_cfg_flag_set(dflag,
2210 			    NSCD_CFG_DFLAG_GROUP);
2211 			dflag = _nscd_cfg_flag_set(dflag,
2212 			    NSCD_CFG_DFLAG_BIT_SELECTED);
2213 		} else {
2214 			/*
2215 			 * send param data or group data:
2216 			 * param data - non-xero desc->p_offset
2217 			 * group data - zero desc->p_offset
2218 			 */
2219 			cdata = (char *)data + desc->p_offset;
2220 
2221 			/*
2222 			 * if variable length data, need to send pointer
2223 			 * to the data (not the address of the pointer)
2224 			 */
2225 			if (_nscd_cfg_flag_is_set(desc->pflag,
2226 			    NSCD_CFG_PFLAG_VLEN_DATA))
2227 				cdata = *(char **)cdata;
2228 		}
2229 
2230 		verify_data:
2231 
2232 		if (desc->verify != NULL) {
2233 			dflag = _nscd_cfg_flag_set(dflag,
2234 			    NSCD_CFG_DFLAG_VERIFY);
2235 			rc = desc->verify(cdata, desc, nswdb,
2236 			    dflag, errorp, &cookie);
2237 			if (rc != NSCD_SUCCESS)
2238 				goto error_exit;
2239 		}
2240 
2241 		if (desc->notify != NULL) {
2242 			dflag = _nscd_cfg_flag_set(dflag,
2243 			    NSCD_CFG_DFLAG_NOTIFY);
2244 
2245 			rc = desc->notify(data, desc, nswdb,
2246 			    dflag, errorp, cookie);
2247 			if (rc != NSCD_SUCCESS)
2248 				goto error_exit;
2249 		}
2250 	}
2251 
2252 	rc = NSCD_SUCCESS;
2253 
2254 	error_exit:
2255 
2256 	/* restore the bitmap in the input data */
2257 	if (bitmap_addr != NULL)
2258 		_nscd_cfg_bitmap_set(bitmap_addr, bitmap_in);
2259 
2260 	return (rc);
2261 }
2262 
2263 /*
2264  * Convert string 'str' to data based on the data type in 'desc'.
2265  * 'data' points to the buffer in which the converted data
2266  * is placed. '*data_p' points to the buffer, or in the case
2267  * of a string data type, points to the untoched string (i.e.,
2268  * 'str').
2269  */
2270 nscd_rc_t
2271 _nscd_cfg_str_to_data(
2272 	nscd_cfg_param_desc_t	*desc,
2273 	char			*str,
2274 	void			*data,
2275 	void			**data_p,
2276 	nscd_cfg_error_t	**errorp)
2277 {
2278 
2279 	char			*me = "_nscd_cfg_str_to_data";
2280 	char			*c;
2281 	nscd_cfg_bitmap_t	bitmap;
2282 	char			msg[NSCD_CFG_MAX_ERR_MSG_LEN];
2283 	nscd_rc_t		rc = NSCD_CFG_DATA_CONVERSION_FAILED;
2284 
2285 	if (desc == NULL || str == NULL || data == NULL) {
2286 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2287 		(me, "ERROR: one of the following is NULL "
2288 		    "desc = %p, str = %p, data = %p, data_p = %p\n",
2289 		    desc, str, data, data_p);
2290 
2291 		return (NSCD_INVALID_ARGUMENT);
2292 	}
2293 	*data_p = data;
2294 
2295 	/* if description is that of a group, return error */
2296 	if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) {
2297 
2298 		(void) snprintf(msg, sizeof (msg),
2299 		gettext("single data specified for group %s"), desc->id.name);
2300 
2301 		if (errorp != NULL)
2302 			*errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT,
2303 			    msg);
2304 
2305 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2306 		(me, "ERROR: %s)\n", msg);
2307 
2308 		return (NSCD_INVALID_ARGUMENT);
2309 
2310 	}
2311 
2312 	if (desc->type == NSCD_CFG_DATA_STRING) {
2313 		if (strcmp(str, NSCD_NULL) == 0)
2314 			*(char **)data_p = NULL;
2315 		else {
2316 			/* remove the " char if quoted string */
2317 			if (str[0] == '"') {
2318 				c = str + strlen(str) - 1;
2319 				if (*c == '"')
2320 					*c = '\0';
2321 				*(char **)data_p = str + 1;
2322 			} else
2323 				*(char **)data_p = str;
2324 
2325 		}
2326 		return (NSCD_SUCCESS);
2327 	}
2328 
2329 	if (str == NULL) {
2330 
2331 		(void) snprintf(msg, sizeof (msg),
2332 		gettext("data must be specified for %s"), desc->id.name);
2333 
2334 		if (errorp != NULL)
2335 			*errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT,
2336 			    msg);
2337 
2338 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2339 		(me, "ERROR: %s\n", msg);
2340 
2341 		return (NSCD_INVALID_ARGUMENT);
2342 
2343 	}
2344 
2345 	switch (desc->type) {
2346 
2347 	case NSCD_CFG_DATA_BOOLEAN:
2348 
2349 		if (strcasecmp(str, "yes") == 0)
2350 			*(nscd_bool_t *)data = nscd_true;
2351 		else if (strcasecmp(str, "no") == 0)
2352 			*(nscd_bool_t *)data = nscd_false;
2353 		else {
2354 
2355 		(void) snprintf(msg, sizeof (msg),
2356 		gettext("data (%s) must be 'yes' or 'no' for %s"),
2357 		    str, desc->id.name);
2358 
2359 		if (errorp != NULL)
2360 			*errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT,
2361 			    msg);
2362 
2363 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2364 			(me, "ERROR: %s\n", msg);
2365 
2366 			return (NSCD_INVALID_ARGUMENT);
2367 		}
2368 
2369 		break;
2370 
2371 	case NSCD_CFG_DATA_INTEGER:
2372 
2373 		errno = 0;
2374 		*(int *)data = (int)strtol(str, (char **)NULL, 10);
2375 		if (errno != NULL) {
2376 
2377 			(void) snprintf(msg, sizeof (msg),
2378 			gettext("unable to convert data (%s) for %s"),
2379 			    str, desc->id.name);
2380 
2381 			if (errorp != NULL)
2382 				*errorp = _nscd_cfg_make_error(rc, msg);
2383 
2384 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2385 			(me, "ERROR: %s\n", msg);
2386 
2387 			return (rc);
2388 		}
2389 
2390 		break;
2391 
2392 	case NSCD_CFG_DATA_BITMAP:
2393 
2394 		errno = 0;
2395 		bitmap = (nscd_cfg_bitmap_t)strtol(str, (char **)NULL, 10);
2396 		if (errno != NULL) {
2397 
2398 			(void) snprintf(msg, sizeof (msg),
2399 			gettext("unable to convert data (%s) for %s"),
2400 			    str, desc->id.name);
2401 
2402 			if (errorp != NULL)
2403 				*errorp = _nscd_cfg_make_error(rc, msg);
2404 
2405 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2406 			(me, "ERROR: %s\n", msg);
2407 
2408 			return (rc);
2409 		}
2410 
2411 		_nscd_cfg_bitmap_set(data, bitmap);
2412 
2413 		break;
2414 
2415 	}
2416 
2417 	return (NSCD_SUCCESS);
2418 }
2419 
2420 
2421 nscd_rc_t
2422 _nscd_cfg_set(
2423 	nscd_cfg_handle_t	*handle,
2424 	void			*data,
2425 	nscd_cfg_error_t	**errorp)
2426 {
2427 	char			*me = "_nscd_cfg_set";
2428 	int			dlen;
2429 	nscd_cfg_id_t		*nswdb;
2430 	nscd_cfg_param_desc_t	*desc, *gdesc;
2431 	nscd_cfg_group_info_t	*gi;
2432 	char			*nswdb_name, *param_name;
2433 	void			*pdata = NULL;
2434 	void			*cfg_data, *vdata_addr = NULL;
2435 	nscd_bool_t		get_group = 0;
2436 	nscd_bool_t		in = nscd_true;
2437 	nscd_cfg_lock_t		*lock = NULL;
2438 	nscd_rc_t		rc = NSCD_SUCCESS;
2439 
2440 	if (handle == NULL) {
2441 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2442 		(me, "handle is NULL\n");
2443 		return (NSCD_INVALID_ARGUMENT);
2444 	}
2445 
2446 	nswdb = handle->nswdb;
2447 	desc = (nscd_cfg_param_desc_t *)handle->desc;
2448 	if (nswdb == NULL)
2449 		nswdb_name = "global";
2450 	else
2451 		nswdb_name = nswdb->name;
2452 	param_name = desc->id.name;
2453 
2454 	if (data == NULL && _nscd_cfg_flag_is_not_set(desc->pflag,
2455 	    NSCD_CFG_PFLAG_VLEN_DATA)) {
2456 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2457 		(me, "data == NULL\n");
2458 		return (NSCD_INVALID_ARGUMENT);
2459 	}
2460 
2461 	if (_nscd_cfg_flag_is_set(desc->pflag,
2462 	    NSCD_CFG_PFLAG_UPDATE_SEND_WHOLE_GROUP) ||
2463 	    _nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP))
2464 		get_group = nscd_true;
2465 
2466 	/*
2467 	 * locate the current value of the param or group
2468 	 * and lock the config data for writing
2469 	 */
2470 	rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_false, desc,
2471 	    nswdb, get_group, &vdata_addr, &dlen, &lock);
2472 	if (rc != NSCD_SUCCESS) {
2473 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2474 		(me, "unable to locate config data (rc = %d)\n", rc);
2475 		return (rc);
2476 	}
2477 
2478 	if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP) &&
2479 	    ((nscd_cfg_group_info_t *)cfg_data)->num_param !=
2480 	    ((nscd_cfg_group_info_t *)data)->num_param) {
2481 
2482 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2483 		(me, "number of parameters in group <%s : %s> not equal: "
2484 		    "%d in input data, should be %d\n",
2485 		    NSCD_STR_OR_GLOBAL(nswdb_name),
2486 		    NSCD_STR_OR_NULL(param_name),
2487 		    ((nscd_cfg_group_info_t *)data)->num_param,
2488 		    ((nscd_cfg_group_info_t *)cfg_data)->num_param);
2489 
2490 		rc = NSCD_INVALID_ARGUMENT;
2491 		goto error_exit;
2492 	}
2493 
2494 	/*
2495 	 * if variable length data, we want the address
2496 	 * of the pointer pointing to the data
2497 	 */
2498 	if (vdata_addr != NULL)
2499 		cfg_data = vdata_addr;
2500 
2501 	/*
2502 	 * just copy in the specified data, if no need
2503 	 * to verify the data or notify the associated
2504 	 * component
2505 	 */
2506 		if (get_group == nscd_true) {
2507 
2508 			gdesc = &_nscd_cfg_param_desc[desc->g_index];
2509 
2510 			rc = _nscd_cfg_copy_group_data_merge(
2511 			    gdesc, &pdata, data, cfg_data,
2512 			    desc->id.index, data);
2513 
2514 			if (rc != NSCD_SUCCESS) {
2515 				_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2516 				(me, "unable to copy group data <%s : %s>\n",
2517 				    NSCD_STR_OR_GLOBAL(nswdb_name),
2518 				    NSCD_STR_OR_NULL(param_name));
2519 
2520 				goto error_exit;
2521 			}
2522 
2523 			rc = _nscd_cfg_notify_s(gdesc, nswdb,
2524 			    pdata, errorp);
2525 
2526 		} else
2527 			rc = _nscd_cfg_notify_s(desc, nswdb, data,
2528 			    errorp);
2529 
2530 		if (rc != NSCD_SUCCESS) {
2531 
2532 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2533 			(me, "verifying/notifying  of new configuration "
2534 			    "parameter <%s : %s> failed. %s\n",
2535 			    NSCD_STR_OR_GLOBAL(nswdb_name),
2536 			    param_name, (*errorp && (*errorp)->msg) ?
2537 			    (*errorp)->msg : "");
2538 
2539 			goto error_exit;
2540 		}
2541 
2542 	/*
2543 	 * Move the new config into the config store
2544 	 */
2545 	rc = NSCD_CFG_SET_PARAM_FAILED;
2546 	if (_nscd_cfg_flag_is_set(desc->pflag,
2547 	    NSCD_CFG_PFLAG_GROUP)) {
2548 		gi = _nscd_cfg_get_gi(pdata);
2549 		rc = _nscd_cfg_copy_group_data_in(gdesc, gi,
2550 		    cfg_data, pdata);
2551 	} else {
2552 		/*
2553 		 * nscd_true asks _nscd_cfg_copy_param_data to
2554 		 * set addr of the vlen data in 'cfg_data' rather
2555 		 * than copying the data content
2556 		 */
2557 		if (pdata != NULL)
2558 			_nscd_cfg_free_vlen_data_group(gdesc,
2559 			    pdata, in);
2560 
2561 		rc = _nscd_cfg_copy_param_data(desc,
2562 		    cfg_data, data, in, nscd_true);
2563 	}
2564 
2565 	if (rc != NSCD_SUCCESS) {
2566 
2567 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2568 		(me, "unable to make new param data <%s : %s> current\n",
2569 		    NSCD_STR_OR_GLOBAL(nswdb_name),
2570 		    NSCD_STR_OR_NULL(param_name));
2571 	}
2572 
2573 	error_exit:
2574 
2575 	_nscd_cfg_unlock(lock);
2576 
2577 	return (rc);
2578 }
2579 
2580 nscd_rc_t
2581 _nscd_cfg_set_linked(
2582 	nscd_cfg_handle_t		*handle,
2583 	void				*data,
2584 	nscd_cfg_error_t		**errorp)
2585 {
2586 	char				*me = "_nscd_cfg_set_linked";
2587 	nscd_cfg_id_t			*nswdb;
2588 	nscd_cfg_handle_t		*hl;
2589 	nscd_cfg_param_desc_t		*desc;
2590 	char				*nswdb_name, *param_name, *dbl;
2591 	nscd_rc_t			rc = NSCD_SUCCESS;
2592 	nscd_cfg_nsw_spc_default_t	*spc;
2593 	int				i;
2594 	char				msg[NSCD_CFG_MAX_ERR_MSG_LEN];
2595 
2596 	if (handle == NULL) {
2597 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2598 		(me, "handle is NULL\n");
2599 		return (NSCD_INVALID_ARGUMENT);
2600 	}
2601 
2602 	nswdb = handle->nswdb;
2603 	desc = (nscd_cfg_param_desc_t *)handle->desc;
2604 
2605 	/*
2606 	 * no need to do the special linking thing,
2607 	 * if a global param, or a group, or not a linked param
2608 	 */
2609 	if (nswdb == NULL || _nscd_cfg_flag_is_set(desc->pflag,
2610 	    NSCD_CFG_PFLAG_GROUP) ||
2611 	    _nscd_cfg_flag_is_not_set(desc->pflag,
2612 	    NSCD_CFG_PFLAG_LINKED))
2613 		return (_nscd_cfg_set(handle, data, errorp));
2614 	else
2615 		nswdb_name = nswdb->name;
2616 	param_name = desc->id.name;
2617 
2618 	/*
2619 	 * if a param is linked to another, it can not be
2620 	 * changed directly
2621 	 */
2622 	for (i = 0; i < _nscd_cfg_num_link_default; i++) {
2623 
2624 		if (_nscd_cfg_nsw_link_default[i].data == NULL)
2625 			continue;
2626 
2627 		if (strcmp(_nscd_cfg_nsw_link_default[i].db,
2628 		    nswdb_name) == 0 &&
2629 		    _nscd_cfg_nsw_link_default[i].group_off ==
2630 		    desc->g_offset &&
2631 		    _nscd_cfg_nsw_link_default[i].param_off ==
2632 		    desc->p_offset) {
2633 
2634 			rc = NSCD_CFG_READ_ONLY;
2635 
2636 			(void) snprintf(msg, sizeof (msg),
2637 			    gettext("value of \'%s\' not changeable, "
2638 			    "change that of \'%s\' instead"),
2639 			    nswdb->name, "passwd");
2640 
2641 			if (errorp != NULL)
2642 				*errorp = _nscd_cfg_make_error(rc, msg);
2643 
2644 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2645 			(me, "ERROR: %s\n", msg);
2646 
2647 			return (rc);
2648 		}
2649 	}
2650 
2651 	/*
2652 	 * if a param is linked from another, it should be verify
2653 	 * and changed first
2654 	 */
2655 	for (i = 0; i < _nscd_cfg_num_link_default; i++) {
2656 
2657 		if (_nscd_cfg_nsw_link_default[i].data == NULL)
2658 			continue;
2659 
2660 		spc = _nscd_cfg_nsw_link_default[i].data;
2661 
2662 		if (strcmp(spc->db, nswdb_name) == 0 &&
2663 		    spc->group_off == desc->g_offset &&
2664 		    spc->param_off == desc->p_offset) {
2665 
2666 			rc = _nscd_cfg_set(handle, data, errorp);
2667 			if (rc != NSCD_SUCCESS)
2668 				return (rc);
2669 			break;
2670 		}
2671 	}
2672 
2673 	/*
2674 	 * then change all those linked to the one that has been changed
2675 	 */
2676 	for (i = 0; i < _nscd_cfg_num_link_default; i++) {
2677 
2678 		if (_nscd_cfg_nsw_link_default[i].data == NULL)
2679 			continue;
2680 
2681 		spc = _nscd_cfg_nsw_link_default[i].data;
2682 
2683 		if (strcmp(spc->db, nswdb_name) == 0 &&
2684 		    spc->group_off == desc->g_offset &&
2685 		    spc->param_off == desc->p_offset &&
2686 		    _nscd_cfg_nsw_link_default[i].group_off ==
2687 		    desc->g_offset &&
2688 		    _nscd_cfg_nsw_link_default[i].param_off ==
2689 		    desc->p_offset) {
2690 
2691 			dbl = _nscd_cfg_nsw_link_default[i].db;
2692 
2693 			rc = _nscd_cfg_get_handle(param_name, dbl,
2694 			    &hl, errorp);
2695 			if (rc != NSCD_SUCCESS)
2696 				return (rc);
2697 			rc = _nscd_cfg_set(hl, data, errorp);
2698 			_nscd_cfg_free_handle(hl);
2699 			if (rc != NSCD_SUCCESS)
2700 				return (rc);
2701 		}
2702 	}
2703 
2704 	return (_nscd_cfg_set(handle, data, errorp));
2705 }
2706 
2707 /*
2708  * Return a list of comma-separated database names that
2709  * have at least one of the input sources (the srcs array)
2710  * appears in their configured nsswitch policy string.
2711  * That is, if srcs contains "ldap" and "passwd: files ldap"
2712  * "group: files ldap" are in /etc/nsswitch.conf, then
2713  * "passwd,group" will be returned. The return string
2714  * should be freed by the caller.
2715  *
2716  * For compat nsswitch configuration, "group" and/or
2717  * "passwd,user_attr,shadow,audit_user" (not "group_compat"
2718  * or "passwd_compat") will be returned. Note that the
2719  * user_attr, shadow, and audit_user databases share the
2720  * same policy with the passwd database.
2721  *
2722  * For example, if srcs has "ldap" and in /etc/nsswitch.conf,
2723  * there are:
2724  *   passwd:		compat
2725  *   passwd_compat:	ldap
2726  *   group:		compat
2727  *   group_compat:	ldap
2728  *   netgroup:		ldap
2729  * then "netgroup,passwd,group,user_attr,shadow,audit_user"
2730  * will be returned.
2731  */
2732 char *
2733 _nscd_srcs_in_db_nsw_policy(
2734 	int			num_src,
2735 	char			**srcs)
2736 {
2737 	uint8_t			i, j, n = 0, nc = 0;
2738 	uint8_t			compat_grp = 0, compat_pwd = 0;
2739 	uint8_t			*db;
2740 	uint8_t			*db_compat;
2741 	int			dlen = 0;
2742 	nscd_cfg_nsw_db_data_t	*dbcfg;
2743 	nscd_cfg_switch_t	*sw;
2744 	char			*outstr = NULL;
2745 	char			*dbname;
2746 
2747 	db = (uint8_t *)calloc(_nscd_cfg_num_nsw_db, sizeof (uint8_t));
2748 	if (db == NULL)
2749 		return (NULL);
2750 
2751 	db_compat = (uint8_t *)calloc(_nscd_cfg_num_nsw_db,
2752 	    sizeof (uint8_t));
2753 	if (db_compat == NULL) {
2754 		free(db);
2755 		return (NULL);
2756 	}
2757 
2758 	for (i = 0; i < _nscd_cfg_num_nsw_db; i++) {
2759 
2760 		(void) rw_rdlock(&nscd_cfg_nsw_db_data_rwlock[i]);
2761 
2762 		dbcfg = &nscd_cfg_nsw_db_data_current[i];
2763 		sw = &dbcfg->sw;
2764 		if (sw->nsw_config_string == NULL) {
2765 			(void) rw_unlock(&nscd_cfg_nsw_db_data_rwlock[i]);
2766 			continue;
2767 		}
2768 
2769 		dbname = _nscd_cfg_nsw_db[i].name;
2770 		for (j = 0; j < num_src; j++) {
2771 			if (strstr(sw->nsw_config_string, srcs[j]) !=
2772 			    NULL) {
2773 				db[n++] = i;
2774 				dlen += strlen(dbname) + 1;
2775 			} else if (strcmp(sw->nsw_config_string,
2776 			    "compat") == 0) {
2777 				if (strcmp(dbname, "passwd") == 0) {
2778 					compat_pwd = 1;
2779 					dlen += 7;
2780 				} else if (strcmp(dbname, "group") == 0) {
2781 					compat_grp = 1;
2782 					dlen += 6;
2783 				} else {
2784 					db_compat[nc++] = i;
2785 					dlen += strlen(dbname) + 1;
2786 
2787 				}
2788 			}
2789 		}
2790 		(void) rw_unlock(&nscd_cfg_nsw_db_data_rwlock[i]);
2791 	}
2792 
2793 	if (dlen != 0)
2794 		outstr = (char *)calloc(1, dlen);
2795 	if (outstr == NULL) {
2796 		free(db_compat);
2797 		free(db);
2798 		return (NULL);
2799 	}
2800 
2801 	for (j = 0; j < n; j++) {
2802 		dbname = _nscd_cfg_nsw_db[db[j]].name;
2803 		if (strstr(dbname, "group_compat") != NULL) {
2804 			if (compat_grp == 1)
2805 				dbname = "group";
2806 			else
2807 				continue;
2808 		} else if (strstr(dbname, "passwd_compat") != NULL) {
2809 			if (compat_pwd == 1)
2810 				dbname = "passwd";
2811 			else
2812 				continue;
2813 		}
2814 
2815 		(void) strlcat(outstr, dbname, dlen);
2816 		(void) strlcat(outstr, ",", dlen);
2817 	}
2818 
2819 	for (j = 0; j < nc; j++) {
2820 		dbname = _nscd_cfg_nsw_db[db_compat[j]].name;
2821 		if (compat_pwd == 1) {
2822 			(void) strlcat(outstr, dbname, dlen);
2823 			(void) strlcat(outstr, ",", dlen);
2824 		}
2825 	}
2826 
2827 	/* remove the last comma */
2828 	i = strlen(outstr) - 1;
2829 	if (outstr[i] == ',')
2830 		outstr[i] = '\0';
2831 
2832 	free(db);
2833 	free(db_compat);
2834 	return (outstr);
2835 
2836 }
2837