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