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