xref: /illumos-gate/usr/src/cmd/nscd/nscd_config.c (revision 68ac2337c38c8af06edcf32a72e42de36ec72a9d)
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 != NSCD_SUCCESS)
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 != NSCD_SUCCESS)
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 != NSCD_SUCCESS)
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 != NSCD_SUCCESS)
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 != NSCD_SUCCESS)
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 != NSCD_SUCCESS)
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; j++) {
1324 
1325 					nswdb = &_nscd_cfg_nsw_db[j];
1326 
1327 					rc = _nscd_cfg_notify_i(desc,
1328 						nswdb, &skip, errorp);
1329 
1330 					if (rc != NSCD_SUCCESS)
1331 						break;
1332 				}
1333 			}
1334 		}
1335 
1336 		if (rc != NSCD_SUCCESS)
1337 			return (rc);
1338 
1339 		i += skip;
1340 	}
1341 
1342 	return (NSCD_SUCCESS);
1343 }
1344 
1345 nscd_rc_t
1346 _nscd_cfg_init(
1347 	nscd_cfg_error_t		**errorp)
1348 {
1349 
1350 	int				i, j, datalen;
1351 	int				dbi = 0, dbj = 0;
1352 	char				*dest, *src;
1353 	char				*dbni = NULL, *dbnj = NULL;
1354 	nscd_rc_t			rc;
1355 	nscd_cfg_nsw_spc_default_t	*spc;
1356 
1357 	if (errorp != NULL)
1358 		*errorp = NULL;
1359 
1360 	rc = _nscd_cfg_init_param();
1361 	if (rc != NSCD_SUCCESS)
1362 		return (rc);
1363 
1364 	rc = _nscd_cfg_init_stat();
1365 	if (rc != NSCD_SUCCESS)
1366 		return (rc);
1367 
1368 	nscd_cfg_global_current = calloc(1,
1369 			sizeof (nscd_cfg_global_data_t));
1370 	if (nscd_cfg_global_current == NULL)
1371 		return (NSCD_NO_MEMORY);
1372 
1373 	nscd_cfg_nsw_alldb_current = calloc(1,
1374 		sizeof (nscd_cfg_nsw_db_data_t));
1375 	if (nscd_cfg_nsw_alldb_current == NULL)
1376 		return (NSCD_NO_MEMORY);
1377 
1378 	nscd_cfg_nsw_db_data_current = calloc(_nscd_cfg_num_nsw_db,
1379 		sizeof (nscd_cfg_nsw_db_data_t));
1380 	if (nscd_cfg_nsw_db_data_current == NULL)
1381 		return (NSCD_NO_MEMORY);
1382 
1383 	nscd_cfg_global_rwlock = calloc(1, sizeof (rwlock_t));
1384 	if (nscd_cfg_global_rwlock == NULL)
1385 		return (NSCD_NO_MEMORY);
1386 	(void) rwlock_init(nscd_cfg_global_rwlock, NULL, NULL);
1387 
1388 	*nscd_cfg_global_current = nscd_cfg_global_default;
1389 
1390 	rc = _nscd_cfg_set_vlen_data_int(&nscd_cfg_global_default,
1391 		nscd_cfg_global_current, nscd_true);
1392 	if (rc != NSCD_SUCCESS)
1393 		return (rc);
1394 
1395 	nscd_cfg_nsw_db_data_rwlock = calloc(_nscd_cfg_num_nsw_db,
1396 		sizeof (rwlock_t));
1397 	if (nscd_cfg_nsw_db_data_rwlock == NULL)
1398 		return (NSCD_NO_MEMORY);
1399 
1400 	/* set per switch db config to the default for all db's */
1401 	for (i = 0; i < _nscd_cfg_num_nsw_db; i++) {
1402 
1403 		nscd_cfg_nsw_db_data_current[i] =
1404 			nscd_cfg_nsw_db_data_default;
1405 
1406 		(void) rwlock_init(&nscd_cfg_nsw_db_data_rwlock[i],
1407 			NULL, NULL);
1408 	}
1409 
1410 	/* add db specific defaults */
1411 	for (i = 0; i < _nscd_cfg_num_nsw_default; i++) {
1412 
1413 		if (_nscd_cfg_nsw_spc_default[i].data == NULL)
1414 			continue;
1415 
1416 		if (_nscd_cfg_nsw_spc_default[i].db != dbni) {
1417 			for (j = 0; j < _nscd_cfg_num_nsw_db; j++) {
1418 
1419 				if (strcmp(_nscd_cfg_nsw_db[j].name,
1420 					_nscd_cfg_nsw_spc_default[i].db) != 0)
1421 					continue;
1422 
1423 				dbi = _nscd_cfg_nsw_db[j].index;
1424 				dbni = _nscd_cfg_nsw_db[j].name;
1425 				break;
1426 			}
1427 		}
1428 
1429 		dest = (char *)&nscd_cfg_nsw_db_data_current[dbi] +
1430 			_nscd_cfg_nsw_spc_default[i].group_off +
1431 			_nscd_cfg_nsw_spc_default[i].param_off;
1432 
1433 		src = _nscd_cfg_nsw_spc_default[i].data;
1434 		datalen = _nscd_cfg_nsw_spc_default[i].data_len;
1435 
1436 		(void) memcpy(dest, src, datalen);
1437 	}
1438 
1439 	/* add db specific defaults via links */
1440 	for (i = 0; i < _nscd_cfg_num_link_default; i++) {
1441 
1442 		if (_nscd_cfg_nsw_link_default[i].data == NULL)
1443 			continue;
1444 
1445 		spc = _nscd_cfg_nsw_link_default[i].data;
1446 
1447 		if (_nscd_cfg_nsw_link_default[i].db != dbni) {
1448 			for (j = 0; j < _nscd_cfg_num_nsw_db; j++) {
1449 
1450 				if (strcmp(_nscd_cfg_nsw_db[j].name,
1451 					_nscd_cfg_nsw_link_default[i].db) != 0)
1452 					continue;
1453 
1454 				dbi = _nscd_cfg_nsw_db[j].index;
1455 				dbni = _nscd_cfg_nsw_db[j].name;
1456 				break;
1457 			}
1458 		}
1459 
1460 		dest = (char *)&nscd_cfg_nsw_db_data_current[dbi] +
1461 			_nscd_cfg_nsw_link_default[i].group_off +
1462 			_nscd_cfg_nsw_link_default[i].param_off;
1463 
1464 		if (_nscd_cfg_nsw_db[j].name != dbnj) {
1465 			for (j = 0; j < _nscd_cfg_num_nsw_db; j++) {
1466 
1467 				if (strcmp(spc->db,
1468 					_nscd_cfg_nsw_db[j].name) != 0)
1469 					continue;
1470 
1471 				dbnj = _nscd_cfg_nsw_db[j].name;
1472 				dbj = _nscd_cfg_nsw_db[j].index;
1473 				break;
1474 			}
1475 		}
1476 
1477 		src = (char *)&nscd_cfg_nsw_db_data_current[dbj] +
1478 				spc->group_off + spc->param_off;
1479 		datalen = spc->data_len;
1480 
1481 		(void) memcpy(dest, src, datalen);
1482 	}
1483 
1484 	/* fix up variable length fields */
1485 	for (i = 0; i < _nscd_cfg_num_nsw_db; i++) {
1486 
1487 		rc = _nscd_cfg_set_vlen_data_int(
1488 			&nscd_cfg_nsw_db_data_current[i],
1489 			&nscd_cfg_nsw_db_data_current[i], nscd_false);
1490 		if (rc != NSCD_SUCCESS)
1491 			return (rc);
1492 	}
1493 
1494 	nscd_cfg_nsw_alldb_rwlock = calloc(1, sizeof (rwlock_t));
1495 	if (nscd_cfg_nsw_alldb_rwlock == NULL)
1496 		return (NSCD_NO_MEMORY);
1497 
1498 	(void) rwlock_init(nscd_cfg_nsw_alldb_rwlock, NULL, NULL);
1499 
1500 	rc = _nscd_cfg_set_vlen_data_int(
1501 		&nscd_cfg_nsw_db_data_default,
1502 		nscd_cfg_nsw_alldb_current, nscd_false);
1503 	if (rc != NSCD_SUCCESS)
1504 		return (rc);
1505 
1506 	/*
1507 	 * notify and send the configuration data to
1508 	 * the nscd components
1509 	 */
1510 	rc = _nscd_cfg_notify_init(errorp);
1511 	if (rc != NSCD_SUCCESS)
1512 		return (rc);
1513 
1514 	return (NSCD_SUCCESS);
1515 }
1516 
1517 static nscd_rc_t
1518 _nscd_cfg_get_handle_common(
1519 	nscd_cfg_list_type_t	type,
1520 	char			*name,
1521 	char			*nswdb_name,
1522 	nscd_cfg_handle_t	**handle,
1523 	nscd_cfg_error_t	**errorp)
1524 {
1525 
1526 	int			i, is_global;
1527 	char			*desc_str;
1528 	nscd_cfg_handle_t	*h;
1529 	nscd_cfg_param_desc_t	*pdesc;
1530 	nscd_cfg_stat_desc_t	*sdesc;
1531 	char			*me = "_nscd_cfg_get_handle_common";
1532 	char			msg[NSCD_CFG_MAX_ERR_MSG_LEN];
1533 	nscd_rc_t		rc = NSCD_INVALID_ARGUMENT;
1534 
1535 	if (handle == NULL) {
1536 
1537 		(void) snprintf(msg, sizeof (msg),
1538 			gettext("address of handle not specified"));
1539 		if (errorp)
1540 			*errorp = _nscd_cfg_make_error(rc, msg);
1541 
1542 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
1543 		(me, "invalid argument: %s\n", msg);
1544 
1545 		return (rc);
1546 	}
1547 
1548 	*handle = NULL;
1549 
1550 	if (name == NULL) {
1551 
1552 		(void) snprintf(msg, sizeof (msg),
1553 			gettext("name not specified"));
1554 		if (errorp)
1555 			*errorp = _nscd_cfg_make_error(rc, msg);
1556 
1557 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
1558 		(me, "invalid argument: %s\n");
1559 
1560 		return (rc);
1561 	}
1562 
1563 	h = calloc(1, sizeof (nscd_cfg_handle_t));
1564 	if (h == NULL)
1565 		return (NSCD_NO_MEMORY);
1566 	h->type = type;
1567 
1568 	if (type == NSCD_CFG_LIST_PARAM)
1569 		desc_str = gettext("configuration parameter");
1570 	else
1571 		desc_str = gettext("statistics");
1572 
1573 	/* get param or stat descriptor */
1574 	i = _nscd_cfg_get_index(name, type);
1575 	if (i != -1) {
1576 
1577 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
1578 		(me, "%s: index of %s is %d\n", desc_str, name, i);
1579 
1580 		if (type == NSCD_CFG_LIST_PARAM) {
1581 			pdesc = &_nscd_cfg_param_desc[i];
1582 			(void) memcpy(&h->desc, &pdesc, sizeof (pdesc));
1583 			is_global = _nscd_cfg_flag_is_set(
1584 				pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL);
1585 
1586 			/* hidden params are not exposed */
1587 			if (_nscd_cfg_flag_is_set(
1588 				pdesc->pflag, NSCD_CFG_PFLAG_HIDDEN))
1589 				i = -1;
1590 
1591 			if (_nscd_cfg_flag_is_set(pdesc->pflag,
1592 					NSCD_CFG_PFLAG_OBSOLETE)) {
1593 				_NSCD_LOG(NSCD_LOG_CONFIG,
1594 					NSCD_LOG_LEVEL_WARNING)
1595 					(me,
1596 			gettext("%s: %s is obsolete and will be ignored\n"),
1597 					desc_str, name);
1598 			}
1599 		} else {
1600 			sdesc = &_nscd_cfg_stat_desc[i];
1601 			(void) memcpy(&h->desc, &sdesc, sizeof (sdesc));
1602 			is_global = _nscd_cfg_flag_is_set(
1603 				sdesc->sflag, NSCD_CFG_SFLAG_GLOBAL);
1604 		}
1605 	}
1606 
1607 	if (i == -1) {
1608 
1609 		(void) snprintf(msg, sizeof (msg),
1610 			gettext("%s: unknown name \"%s\""), desc_str, name);
1611 		if (errorp)
1612 			*errorp = _nscd_cfg_make_error(rc, msg);
1613 
1614 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1615 		(me, "%s\n", msg);
1616 
1617 		free(h);
1618 		return (rc);
1619 	}
1620 
1621 	/*
1622 	 * if the param/stat is not a global one, we need to
1623 	 * know which nsswitch database we are dealing with
1624 	 */
1625 	if (is_global == 0) {
1626 		if (nswdb_name == NULL) {
1627 
1628 			(void) snprintf(msg, sizeof (msg),
1629 			gettext("%s: switch database name not specified"),
1630 				desc_str);
1631 			if (errorp)
1632 				*errorp = _nscd_cfg_make_error(rc, msg);
1633 
1634 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1635 			(me, "%s for non-global param or stat %s\n",
1636 			msg, name);
1637 
1638 			free(h);
1639 			return (rc);
1640 		}
1641 	} else {
1642 
1643 		if (nswdb_name != NULL) {
1644 
1645 			(void) snprintf(msg, sizeof (msg),
1646 	gettext("%s: switch database specified for global data"),
1647 				desc_str);
1648 			if (errorp)
1649 				*errorp = _nscd_cfg_make_error(rc, msg);
1650 
1651 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1652 			(me, "%s %s\n", msg, name);
1653 
1654 			free(h);
1655 			return (rc);
1656 		}
1657 
1658 		*handle = h;
1659 		return (NSCD_SUCCESS);
1660 	}
1661 
1662 	/* get nsw DB id */
1663 	i = _nscd_cfg_get_index(nswdb_name, NSCD_CFG_LIST_NSW_DB);
1664 	if (i != -1) {
1665 
1666 		if (i == NSCD_CFG_NSW_ALLDB_INDEX)
1667 			h->nswdb = &_nscd_cfg_nsw_alldb;
1668 		else
1669 			h->nswdb = &_nscd_cfg_nsw_db[i];
1670 
1671 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
1672 		(me, "%s: index of %s is %d\n",
1673 			desc_str, nswdb_name, i);
1674 	} else {
1675 
1676 		(void) snprintf(msg, sizeof (msg),
1677 			gettext("%s: unknown switch database name \"%s\""),
1678 			desc_str, nswdb_name);
1679 		if (errorp)
1680 			*errorp = _nscd_cfg_make_error(rc, msg);
1681 
1682 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1683 		(me, "%s\n", msg);
1684 
1685 		free(h);
1686 		return (NSCD_CFG_UNSUPPORTED_SWITCH_DB);
1687 	}
1688 
1689 	*handle = h;
1690 
1691 	return (NSCD_SUCCESS);
1692 }
1693 
1694 nscd_rc_t
1695 _nscd_cfg_get_handle(
1696 	char			*param_name,
1697 	char			*nswdb_name,
1698 	nscd_cfg_handle_t	**handle,
1699 	nscd_cfg_error_t	**errorp)
1700 {
1701 
1702 	return (_nscd_cfg_get_handle_common(NSCD_CFG_LIST_PARAM,
1703 		param_name, nswdb_name, handle, errorp));
1704 }
1705 
1706 nscd_rc_t
1707 _nscd_cfg_get_stat_handle(
1708 	char			*stat_name,
1709 	char			*nswdb_name,
1710 	nscd_cfg_handle_t	**handle,
1711 	nscd_cfg_error_t	**errorp)
1712 {
1713 
1714 	return (_nscd_cfg_get_handle_common(NSCD_CFG_LIST_STAT,
1715 		stat_name, nswdb_name, handle, errorp));
1716 }
1717 
1718 void
1719 _nscd_cfg_free_handle(
1720 	nscd_cfg_handle_t	*handle)
1721 {
1722 
1723 	free(handle);
1724 
1725 }
1726 
1727 static void
1728 _nscd_cfg_free_vlen_data_group(
1729 	nscd_cfg_param_desc_t	*gdesc,
1730 	void			*group_data,
1731 	nscd_bool_t		in)
1732 {
1733 	int			num;
1734 	void			*dest, *ptr;
1735 	nscd_cfg_param_desc_t	*desc;
1736 
1737 	desc = gdesc;
1738 
1739 	num = ((nscd_cfg_group_info_t *)group_data)->num_param;
1740 
1741 	while (num-- > 0) {
1742 
1743 		desc++;
1744 
1745 		/* skip fixed length data */
1746 		if (_nscd_cfg_flag_is_not_set(desc->pflag,
1747 				NSCD_CFG_PFLAG_VLEN_DATA))
1748 			continue;
1749 
1750 		dest = (char *)group_data + desc->p_offset;
1751 		ptr = *(char **)dest;
1752 		if (ptr == NULL)
1753 			continue;
1754 		if (in == nscd_true)
1755 			_nscd_cfg_free_vlen_data_int(ptr);
1756 		else
1757 			free(ptr);
1758 	}
1759 }
1760 
1761 void
1762 _nscd_cfg_free_param_data(
1763 	void			*data)
1764 {
1765 
1766 	if (data == NULL)
1767 		return;
1768 
1769 	free(data);
1770 }
1771 
1772 void
1773 _nscd_cfg_free_group_data(
1774 	nscd_cfg_handle_t	*handle,
1775 	void			*data)
1776 {
1777 
1778 	nscd_cfg_param_desc_t	*desc;
1779 	nscd_cfg_group_info_t	*gi;
1780 
1781 	if (handle == NULL || data == NULL)
1782 		return;
1783 
1784 	desc = _nscd_cfg_get_desc(handle);
1785 	gi = (nscd_cfg_group_info_t *)data;
1786 	if (desc->p_fn != gi->num_param)
1787 		return;
1788 
1789 	_nscd_cfg_free_vlen_data_group(desc, data, nscd_false);
1790 
1791 	free(data);
1792 }
1793 
1794 void
1795 _nscd_cfg_free_error(
1796 	nscd_cfg_error_t	*error)
1797 {
1798 
1799 	if (error == NULL)
1800 		return;
1801 
1802 	free(error);
1803 }
1804 
1805 static nscd_rc_t
1806 _nscd_cfg_copy_param_data(
1807 	nscd_cfg_param_desc_t	*desc,
1808 	void			*dest,
1809 	void			*pdata,
1810 	nscd_bool_t		in,
1811 	nscd_bool_t		set_addr)
1812 {
1813 
1814 	char			*me = "_nscd_cfg_copy_param_data";
1815 	void			*tmp;
1816 	int			dlen;
1817 	nscd_rc_t		rc = NSCD_SUCCESS;
1818 
1819 	if (desc == NULL || dest == NULL) {
1820 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1821 		(me, "input desc == %p, dest == %p\n", desc, dest);
1822 		return (NSCD_INVALID_ARGUMENT);
1823 	}
1824 
1825 	/* fixed length data */
1826 	if (_nscd_cfg_flag_is_not_set(desc->pflag,
1827 			NSCD_CFG_PFLAG_VLEN_DATA)) {
1828 		(void) memcpy(dest, pdata, desc->p_size);
1829 		goto done;
1830 	}
1831 
1832 
1833 	/* variable length data from this point on */
1834 
1835 	/* make a copy of the variable length data */
1836 	rc = _nscd_cfg_copy_vlen_data(pdata, &tmp, desc, &dlen, in);
1837 	if (rc != NSCD_SUCCESS)
1838 		goto done;
1839 
1840 	if (in == nscd_true) { /* data to internal */
1841 
1842 		/* free the variable length data in the config store */
1843 		if (*(char **)dest != NULL)
1844 			_nscd_cfg_free_vlen_data_int(*(char **)dest);
1845 	}
1846 
1847 	if (set_addr == nscd_true) {
1848 		/*
1849 		 * set the addr of the vlen data
1850 		 */
1851 		*(char **)dest = tmp;
1852 	} else {
1853 		/*
1854 		 * copy the data content (not address)
1855 		 */
1856 		(void) memcpy(dest, tmp, dlen);
1857 	}
1858 
1859 	done:
1860 
1861 	return (rc);
1862 }
1863 
1864 static nscd_rc_t
1865 _nscd_cfg_copy_group_data_in(
1866 	nscd_cfg_param_desc_t	*gdesc,
1867 	nscd_cfg_group_info_t	*gi,
1868 	void			*group_dest,
1869 	void			*group_src)
1870 {
1871 	int			i, num;
1872 	nscd_cfg_param_desc_t	*desc;
1873 	void			*src, *dest;
1874 
1875 	i = 0;
1876 	num = gi->num_param;
1877 	desc = gdesc;
1878 
1879 	while (num-- > 0) {
1880 
1881 		desc++;
1882 
1883 		/* if member not selected by bitmap, skip */
1884 		if (_nscd_cfg_bitmap_is_not_set(gi->bitmap, i++))
1885 			continue;
1886 
1887 		src = (char *)group_src + desc->p_offset;
1888 		dest = (char *)group_dest + desc->p_offset;
1889 
1890 		/*
1891 		 * if variable length data, free and replace the old
1892 		 * with the new
1893 		 */
1894 		if (_nscd_cfg_flag_is_set(desc->pflag,
1895 				NSCD_CFG_PFLAG_VLEN_DATA)) {
1896 			_nscd_cfg_free_vlen_data_int(*(char **)dest);
1897 			*(char **)dest = *(char **)src;
1898 			*(char **)src = NULL;
1899 		} else {
1900 			/*
1901 			 * fixed length data, just copy it
1902 			 */
1903 			(void) memcpy(dest, src, desc->p_size);
1904 		}
1905 	}
1906 
1907 	return (NSCD_SUCCESS);
1908 }
1909 
1910 static nscd_rc_t
1911 _nscd_cfg_copy_group_data_out(
1912 	nscd_cfg_param_desc_t	*gdesc,
1913 	void			*group_dest,
1914 	void			*group_src)
1915 {
1916 
1917 	char			*me = "_nscd_cfg_copy_group_data_out";
1918 	void			*src, *dest;
1919 	int			dlen;
1920 	int			num;
1921 	nscd_cfg_group_info_t	*gi;
1922 	nscd_rc_t		rc = NSCD_SUCCESS;
1923 	nscd_cfg_param_desc_t	*desc;
1924 
1925 	if (group_dest == NULL) {
1926 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1927 		(me, "input group_dest = NULL\n");
1928 		return (NSCD_INVALID_ARGUMENT);
1929 	}
1930 
1931 	gi = _nscd_cfg_get_gi(group_src);
1932 	num = gi->num_param;
1933 	desc = gdesc;
1934 
1935 	while (num-- > 0) {
1936 
1937 		desc++;
1938 
1939 		dest = (char *)group_dest + desc->p_offset;
1940 		src = (char *)group_src + desc->p_offset;
1941 
1942 		/*
1943 		 * if variable length data, get the real
1944 		 * address and length of the data
1945 		 */
1946 		if (_nscd_cfg_flag_is_set(desc->pflag,
1947 				NSCD_CFG_PFLAG_VLEN_DATA)) {
1948 			src = _nscd_cfg_locate_vlen_data(src, &dlen);
1949 			if (dlen == NULL)
1950 				continue;
1951 		}
1952 
1953 		/*
1954 		 * The nscd_true asks _nscd_cfg_copy_param_data
1955 		 * to set addr of the vlen data in 'dest' rather
1956 		 * than copying the data content
1957 		 */
1958 		rc = _nscd_cfg_copy_param_data(desc, dest, src,
1959 			nscd_false, nscd_true);
1960 		if (rc != NSCD_SUCCESS) {
1961 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
1962 			(me, "unable to copy param data for %s\n",
1963 				desc->id.name);
1964 
1965 			_nscd_cfg_free_vlen_data_group(gdesc,
1966 				group_dest, nscd_false);
1967 
1968 			free(group_dest);
1969 
1970 			return (rc);
1971 		}
1972 	}
1973 
1974 	/*
1975 	 * set group bitmap
1976 	 */
1977 	(void) memcpy(group_dest, group_src,
1978 		sizeof (nscd_cfg_group_info_t));
1979 
1980 	return (rc);
1981 }
1982 
1983 
1984 /*
1985  * group_cfg is needed always; group_src may be NULL if
1986  * param_index not zero and pdata not NULL; group_cfg and
1987  * pdata should not be both non-NULL
1988  */
1989 static nscd_rc_t
1990 _nscd_cfg_copy_group_data_merge(
1991 	nscd_cfg_param_desc_t	*gdesc,
1992 	void			**group_dest,
1993 	void			*group_src,
1994 	void			*group_cfg,
1995 	int			param_index,
1996 	void			*pdata)
1997 {
1998 
1999 	char			*me = "_nscd_cfg_copy_group_data_merge";
2000 	void			*src, *dest, *tmp_dest = NULL;
2001 	int			num, i = 0;
2002 	nscd_cfg_group_info_t	*gi;
2003 	nscd_rc_t		rc = NSCD_SUCCESS;
2004 	nscd_cfg_param_desc_t	*desc;
2005 	nscd_cfg_bitmap_t	bitmap;
2006 
2007 	if (group_dest == NULL) {
2008 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2009 		(me, "input **group_dest == NULL\n");
2010 		return (NSCD_INVALID_ARGUMENT);
2011 	}
2012 
2013 	if (group_cfg == NULL) {
2014 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2015 		(me, "input **group_cfg == NULL\n");
2016 		return (NSCD_INVALID_ARGUMENT);
2017 	}
2018 
2019 	if (param_index != NULL && pdata == NULL) {
2020 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2021 		(me, "param_index != NULL but pdata == %p\n", pdata);
2022 		return (NSCD_INVALID_ARGUMENT);
2023 	}
2024 
2025 	tmp_dest = calloc(1, gdesc->g_size);
2026 	if (tmp_dest == NULL)
2027 		return (NSCD_NO_MEMORY);
2028 
2029 	if (group_src != NULL)
2030 		gi = _nscd_cfg_get_gi(group_src);
2031 	else {
2032 		gi = _nscd_cfg_get_gi(group_cfg);
2033 		bitmap = NSCD_CFG_BITMAP_ZERO;
2034 	}
2035 
2036 	num = gi->num_param;
2037 	desc = gdesc;
2038 
2039 	while (num-- > 0) {
2040 
2041 		desc++;
2042 
2043 		dest = (char *)tmp_dest + desc->p_offset;
2044 
2045 		/*
2046 		 * if member not selected by bitmap in group_src,
2047 		 * get the member data in group_cfg
2048 		 */
2049 		if (_nscd_cfg_bitmap_is_not_set(gi->bitmap, i++) ||
2050 				group_src == NULL) {
2051 			src = (char *)group_cfg + desc->p_offset;
2052 		} else
2053 			src = (char *)group_src + desc->p_offset;
2054 
2055 		if (desc->id.index == param_index) {
2056 
2057 			/* use the param data in pdata if provided */
2058 			src = pdata;
2059 			_nscd_cfg_bitmap_set_nth(bitmap, i);
2060 		}
2061 
2062 		/*
2063 		 * if variable length data, get to the data
2064 		 * instead of pointer to the data
2065 		 */
2066 		if (_nscd_cfg_flag_is_set(desc->pflag,
2067 			NSCD_CFG_PFLAG_VLEN_DATA))
2068 				src = *(char **)src;
2069 
2070 		/*
2071 		 * nscd_true asks _nscd_cfg_copy_param_data to
2072 		 * set addr of the vlen data in 'dest' rather
2073 		 * than copying the data content
2074 		 */
2075 		rc = _nscd_cfg_copy_param_data(desc, dest, src,
2076 			nscd_true, nscd_true);
2077 		if (rc != NSCD_SUCCESS) {
2078 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2079 			(me, "unable to copy param data for %s\n",
2080 				desc->id.name);
2081 
2082 			_nscd_cfg_free_vlen_data_group(gdesc,
2083 				tmp_dest, nscd_true);
2084 
2085 			free(tmp_dest);
2086 
2087 			return (rc);
2088 		}
2089 	}
2090 
2091 	*group_dest = tmp_dest;
2092 
2093 	/*
2094 	 * set bitmap: if input is group data, use the one
2095 	 * given; if input is param data, use the one computed
2096 	 * above
2097 	 */
2098 	if (group_src != NULL)
2099 		(void) memcpy(*group_dest, group_src,
2100 			sizeof (nscd_cfg_group_info_t));
2101 	else {
2102 		gi = _nscd_cfg_get_gi(*group_dest);
2103 		_nscd_cfg_bitmap_set(&gi->bitmap, bitmap);
2104 	}
2105 
2106 	return (rc);
2107 }
2108 
2109 /* ARGSUSED */
2110 nscd_rc_t
2111 _nscd_cfg_get(
2112 	nscd_cfg_handle_t	*handle,
2113 	void			**data,
2114 	int			*data_len,
2115 	nscd_cfg_error_t	**errorp)
2116 {
2117 	char			*me = "_nscd_cfg_get";
2118 	int			dlen;
2119 	nscd_rc_t		rc = NSCD_SUCCESS;
2120 	nscd_cfg_id_t		*nswdb;
2121 	nscd_cfg_param_desc_t	*desc;
2122 	void			*cfg_data, *ptr = NULL;
2123 	nscd_bool_t		get_group = nscd_false;
2124 	nscd_bool_t		out = nscd_false;
2125 	nscd_cfg_lock_t		*lock = NULL;
2126 
2127 	if (data_len != NULL)
2128 		*data_len = 0;
2129 
2130 	if (data == NULL) {
2131 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2132 		(me, "input data = %p\n", data);
2133 		return (NSCD_INVALID_ARGUMENT);
2134 	}
2135 
2136 	*data = NULL;
2137 
2138 	if (handle == NULL) {
2139 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2140 		(me, "handle is NULL\n");
2141 		return (NSCD_INVALID_ARGUMENT);
2142 	}
2143 
2144 	nswdb = handle->nswdb;
2145 	desc = (nscd_cfg_param_desc_t *)handle->desc;
2146 
2147 	if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP))
2148 		get_group = nscd_true;
2149 
2150 	/*
2151 	 * locate the current value of the param or group
2152 	 * and lock the config data for reading
2153 	 */
2154 	rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_true, desc,
2155 		nswdb, get_group, NULL, &dlen, &lock);
2156 	if (rc != NSCD_SUCCESS) {
2157 
2158 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2159 		(me, "unable to locate config data\n");
2160 		return (rc);
2161 
2162 	} else if (cfg_data == NULL) /* NULL vlen data */
2163 		goto done;
2164 
2165 	ptr = calloc(1, dlen);
2166 	if (ptr == NULL) {
2167 		rc = NSCD_NO_MEMORY;
2168 		goto error_exit;
2169 	}
2170 
2171 	if (get_group == nscd_true) {
2172 
2173 		rc = _nscd_cfg_copy_group_data_out(desc, ptr, cfg_data);
2174 		if (rc != NSCD_SUCCESS) {
2175 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2176 			(me, "unable to copy group data %p: "
2177 			"error = %d\n", cfg_data, rc);
2178 
2179 			goto error_exit;
2180 		}
2181 	} else {
2182 		/*
2183 		 * nscd_false asks _nscd_cfg_copy_param_data to
2184 		 * copy the data content rather than just setting
2185 		 * the addr of the vlen data in 'ptr'
2186 		 */
2187 		rc = _nscd_cfg_copy_param_data(desc, ptr, cfg_data,
2188 			out, nscd_false);
2189 
2190 		if (rc != NSCD_SUCCESS) {
2191 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2192 			(me, "unable to copy param data %p: "
2193 			"error = %d\n", cfg_data, rc);
2194 
2195 			goto error_exit;
2196 		}
2197 	}
2198 
2199 	*data = ptr;
2200 
2201 	done:
2202 
2203 	if (data_len != NULL)
2204 		*data_len = dlen;
2205 
2206 	_nscd_cfg_unlock(lock);
2207 
2208 	return (NSCD_SUCCESS);
2209 
2210 	error_exit:
2211 
2212 	_nscd_cfg_unlock(lock);
2213 	if (ptr != NULL)
2214 		free(ptr);
2215 
2216 	return (rc);
2217 }
2218 
2219 /*
2220  * three type of data:
2221  * 1 - single param
2222  * 	desc is that of the param
2223  * 2 - single param to be sent in a group
2224  *	a single bit is set in the bitmap,
2225  * 	desc is that of the group
2226  * 3 - group data
2227  *	one of more bits are set in the bitmap,
2228  * 	desc is that of the group
2229  */
2230 static nscd_rc_t
2231 _nscd_cfg_notify_s(
2232 	nscd_cfg_param_desc_t	*desc,
2233 	nscd_cfg_id_t		*nswdb,
2234 	void			*data,
2235 	nscd_cfg_error_t	**errorp)
2236 {
2237 	int			i, num, is_group = 0;
2238 	void			*cookie = NULL;
2239 	void			*cdata;
2240 	nscd_rc_t		rc;
2241 	nscd_cfg_flag_t		dflag, dflag1;
2242 	nscd_cfg_bitmap_t	bitmap_s, bitmap_in, *bitmap_addr = NULL;
2243 	nscd_cfg_group_info_t	*gi;
2244 
2245 	if (errorp != NULL)
2246 		*errorp = NULL;
2247 
2248 	/*
2249 	 * Set data flag going with data to be sent to the
2250 	 * verify/notify routines. To allow the config flag
2251 	 * be exipandable, set the bits one by one.
2252 	 */
2253 	dflag = NSCD_CFG_FLAG_ZERO;
2254 	dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_STATIC_DATA);
2255 	if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) {
2256 		dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_GROUP);
2257 		is_group = 1;
2258 	}
2259 	if (nswdb != NULL &&
2260 		strcmp(NSCD_CFG_NSW_ALLDB, nswdb->name) == 0)
2261 		dflag = _nscd_cfg_flag_set(dflag,
2262 				NSCD_CFG_DFLAG_SET_ALL_DB);
2263 
2264 	/*
2265 	 * the bitmap in the input data may be replaced before
2266 	 * sending to the components, so save the bitmap for
2267 	 * later use
2268 	 */
2269 	if (is_group == 1) {
2270 		gi = _nscd_cfg_get_gi(data);
2271 		bitmap_in = gi->bitmap;
2272 		bitmap_addr = &(gi->bitmap);
2273 
2274 		if (_nscd_cfg_flag_is_set(desc->pflag,
2275 			NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP))
2276 			/* send the entire group just once */
2277 			num = 1;
2278 
2279 		else { /* send individual members one by one */
2280 
2281 			num = desc->p_fn;
2282 
2283 			/*
2284 			 * skip the first desc which is for the group
2285 			 * and get to the desc for the first member
2286 			 */
2287 			desc++;
2288 
2289 			dflag = _nscd_cfg_flag_unset(dflag,
2290 				NSCD_CFG_DFLAG_GROUP);
2291 		}
2292 	} else {
2293 		/* not group data, send the member once */
2294 			num = 1;
2295 	}
2296 
2297 	dflag1 = dflag;
2298 	for (i = 0; i < num; i++, desc++) {
2299 
2300 		dflag = dflag1;
2301 
2302 		if (is_group == 0) {
2303 			cdata = data;
2304 			goto verify_data;
2305 		}
2306 
2307 		if (_nscd_cfg_flag_is_set(desc->pflag,
2308 				NSCD_CFG_PFLAG_SEND_BIT_SELECTED)) {
2309 
2310 			/* set the bitmap to select just this member */
2311 			bitmap_s = NSCD_CFG_BITMAP_ZERO;
2312 			_nscd_cfg_bitmap_set_nth(bitmap_s, i);
2313 			/* replace the bitmap in the input data */
2314 			_nscd_cfg_bitmap_set(bitmap_addr, bitmap_s);
2315 
2316 			/*
2317 			 * send the whole group but with only one
2318 			 * member selected
2319 			 */
2320 			cdata = data;
2321 
2322 			dflag = _nscd_cfg_flag_set(dflag,
2323 				NSCD_CFG_DFLAG_GROUP);
2324 			dflag = _nscd_cfg_flag_set(dflag,
2325 				NSCD_CFG_DFLAG_BIT_SELECTED);
2326 		} else {
2327 			/*
2328 			 * send param data or group data:
2329 			 * param data - non-xero desc->p_offset
2330 			 * group data - zero desc->p_offset
2331 			 */
2332 			cdata = (char *)data + desc->p_offset;
2333 
2334 			/*
2335 			 * if variable length data, need to send pointer
2336 			 * to the data (not the address of the pointer)
2337 			 */
2338 			if (_nscd_cfg_flag_is_set(desc->pflag,
2339 				NSCD_CFG_PFLAG_VLEN_DATA))
2340 				cdata = *(char **)cdata;
2341 		}
2342 
2343 		verify_data:
2344 
2345 		if (desc->verify != NULL) {
2346 			dflag = _nscd_cfg_flag_set(dflag,
2347 				NSCD_CFG_DFLAG_VERIFY);
2348 			rc = desc->verify(cdata, desc, nswdb,
2349 				dflag, errorp, &cookie);
2350 			if (rc != NSCD_SUCCESS)
2351 				goto error_exit;
2352 		}
2353 
2354 		if (desc->notify != NULL) {
2355 			dflag = _nscd_cfg_flag_set(dflag,
2356 				NSCD_CFG_DFLAG_NOTIFY);
2357 
2358 			rc = desc->notify(data, desc, nswdb,
2359 				dflag, errorp, cookie);
2360 			if (rc != NSCD_SUCCESS)
2361 				goto error_exit;
2362 		}
2363 	}
2364 
2365 	rc = NSCD_SUCCESS;
2366 
2367 	error_exit:
2368 
2369 	/* restore the bitmap in the input data */
2370 	if (bitmap_addr != NULL)
2371 		_nscd_cfg_bitmap_set(bitmap_addr, bitmap_in);
2372 
2373 	return (rc);
2374 }
2375 
2376 /*
2377  * Convert string 'str' to data based on the data type in 'desc'.
2378  * 'data' points to the buffer in which the converted data
2379  * is placed. '*data_p' points to the buffer, or in the case
2380  * of a string data type, points to the untoched string (i.e.,
2381  * 'str').
2382  */
2383 nscd_rc_t
2384 _nscd_cfg_str_to_data(
2385 	nscd_cfg_param_desc_t	*desc,
2386 	char			*str,
2387 	void			*data,
2388 	void			**data_p,
2389 	nscd_cfg_error_t	**errorp)
2390 {
2391 
2392 	char			*me = "_nscd_cfg_str_to_data";
2393 	char			*c;
2394 	nscd_cfg_bitmap_t	bitmap;
2395 	char			msg[NSCD_CFG_MAX_ERR_MSG_LEN];
2396 	nscd_rc_t		rc = NSCD_CFG_DATA_CONVERSION_FAILED;
2397 
2398 	if (desc == NULL || str == NULL || data == NULL) {
2399 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2400 		(me, "ERROR: one of the following is NULL "
2401 		"desc = %p, str = %p, data = %p, data_p = %p\n",
2402 		desc, str, data, data_p);
2403 
2404 		return (NSCD_INVALID_ARGUMENT);
2405 	}
2406 	*data_p = data;
2407 
2408 	/* if description is that of a group, return error */
2409 	if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) {
2410 
2411 		(void) snprintf(msg, sizeof (msg),
2412 		gettext("single data specified for group %s"), desc->id.name);
2413 
2414 		if (errorp != NULL)
2415 			*errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT,
2416 				msg);
2417 
2418 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2419 		(me, "ERROR: %s)\n", msg);
2420 
2421 		return (NSCD_INVALID_ARGUMENT);
2422 
2423 	}
2424 
2425 	if (desc->type == NSCD_CFG_DATA_STRING) {
2426 		if (strcmp(str, NSCD_NULL) == 0)
2427 			*(char **)data_p = NULL;
2428 		else {
2429 			/* remove the " char if quoted string */
2430 			if (str[0] == '"') {
2431 				c = str + strlen(str) - 1;
2432 				if (*c == '"')
2433 					*c = '\0';
2434 				*(char **)data_p = str + 1;
2435 			} else
2436 				*(char **)data_p = str;
2437 
2438 		}
2439 		return (NSCD_SUCCESS);
2440 	}
2441 
2442 	if (str == NULL) {
2443 
2444 		(void) snprintf(msg, sizeof (msg),
2445 		gettext("data must be specified for %s"), desc->id.name);
2446 
2447 		if (errorp != NULL)
2448 			*errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT,
2449 				msg);
2450 
2451 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2452 		(me, "ERROR: %s\n", msg);
2453 
2454 		return (NSCD_INVALID_ARGUMENT);
2455 
2456 	}
2457 
2458 	switch (desc->type) {
2459 
2460 	case NSCD_CFG_DATA_BOOLEAN:
2461 
2462 		if (strcasecmp(str, "yes") == 0)
2463 			*(nscd_bool_t *)data = nscd_true;
2464 		else if (strcasecmp(str, "no") == 0)
2465 			*(nscd_bool_t *)data = nscd_false;
2466 		else {
2467 
2468 		(void) snprintf(msg, sizeof (msg),
2469 		gettext("data (%s) must be 'yes' or 'no' for %s"),
2470 				str, desc->id.name);
2471 
2472 		if (errorp != NULL)
2473 			*errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT,
2474 				msg);
2475 
2476 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2477 			(me, "ERROR: %s\n", msg);
2478 
2479 			return (NSCD_INVALID_ARGUMENT);
2480 		}
2481 
2482 		break;
2483 
2484 	case NSCD_CFG_DATA_INTEGER:
2485 
2486 		errno = 0;
2487 		*(int *)data = (int)strtol(str, (char **)NULL, 10);
2488 		if (errno != NULL) {
2489 
2490 			(void) snprintf(msg, sizeof (msg),
2491 			gettext("unable to convert data (%s) for %s"),
2492 				str, desc->id.name);
2493 
2494 			if (errorp != NULL)
2495 				*errorp = _nscd_cfg_make_error(rc, msg);
2496 
2497 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2498 			(me, "ERROR: %s\n", msg);
2499 
2500 			return (rc);
2501 		}
2502 
2503 		break;
2504 
2505 	case NSCD_CFG_DATA_BITMAP:
2506 
2507 		errno = 0;
2508 		bitmap = (nscd_cfg_bitmap_t)strtol(str, (char **)NULL, 10);
2509 		if (errno != NULL) {
2510 
2511 			(void) snprintf(msg, sizeof (msg),
2512 			gettext("unable to convert data (%s) for %s"),
2513 				str, desc->id.name);
2514 
2515 			if (errorp != NULL)
2516 				*errorp = _nscd_cfg_make_error(rc, msg);
2517 
2518 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2519 			(me, "ERROR: %s\n", msg);
2520 
2521 			return (rc);
2522 		}
2523 
2524 		_nscd_cfg_bitmap_set(data, bitmap);
2525 
2526 		break;
2527 
2528 	}
2529 
2530 	return (NSCD_SUCCESS);
2531 }
2532 
2533 
2534 nscd_rc_t
2535 _nscd_cfg_set(
2536 	nscd_cfg_handle_t	*handle,
2537 	void			*data,
2538 	nscd_cfg_error_t	**errorp)
2539 {
2540 	char			*me = "_nscd_cfg_set";
2541 	int			dlen;
2542 	nscd_cfg_id_t		*nswdb;
2543 	nscd_cfg_param_desc_t	*desc, *gdesc;
2544 	nscd_cfg_group_info_t	*gi;
2545 	char			*nswdb_name, *param_name;
2546 	void			*pdata = NULL;
2547 	void			*cfg_data, *vdata_addr = NULL;
2548 	nscd_bool_t		get_group = 0;
2549 	nscd_bool_t		in = nscd_true;
2550 	nscd_cfg_lock_t		*lock = NULL;
2551 	nscd_rc_t		rc = NSCD_SUCCESS;
2552 
2553 	if (handle == NULL) {
2554 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2555 		(me, "handle is NULL\n");
2556 		return (NSCD_INVALID_ARGUMENT);
2557 	}
2558 
2559 	nswdb = handle->nswdb;
2560 	desc = (nscd_cfg_param_desc_t *)handle->desc;
2561 	if (nswdb == NULL)
2562 		nswdb_name = "global";
2563 	else
2564 		nswdb_name = nswdb->name;
2565 	param_name = desc->id.name;
2566 
2567 	if (data == NULL && _nscd_cfg_flag_is_not_set(desc->pflag,
2568 			NSCD_CFG_PFLAG_VLEN_DATA)) {
2569 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2570 		(me, "data == NULL\n");
2571 		return (NSCD_INVALID_ARGUMENT);
2572 	}
2573 
2574 	if (_nscd_cfg_flag_is_set(desc->pflag,
2575 			NSCD_CFG_PFLAG_UPDATE_SEND_WHOLE_GROUP) ||
2576 		_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP))
2577 		get_group = nscd_true;
2578 
2579 	/*
2580 	 * locate the current value of the param or group
2581 	 * and lock the config data for writing
2582 	 */
2583 	rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_false, desc,
2584 		nswdb, get_group, &vdata_addr, &dlen, &lock);
2585 	if (rc != NSCD_SUCCESS) {
2586 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2587 		(me, "unable to locate config data (rc = %d)\n", rc);
2588 		return (rc);
2589 	}
2590 
2591 	if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP) &&
2592 		((nscd_cfg_group_info_t *)cfg_data)->num_param !=
2593 		((nscd_cfg_group_info_t *)data)->num_param) {
2594 
2595 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2596 		(me, "number of parameters in group <%s : %s> not equal: "
2597 		"%d in input data, should be %d\n",
2598 		NSCD_STR_OR_GLOBAL(nswdb_name),
2599 		NSCD_STR_OR_NULL(param_name),
2600 		((nscd_cfg_group_info_t *)data)->num_param,
2601 		((nscd_cfg_group_info_t *)cfg_data)->num_param);
2602 
2603 		rc = NSCD_INVALID_ARGUMENT;
2604 		goto error_exit;
2605 	}
2606 
2607 	/*
2608 	 * if variable length data, we want the address
2609 	 * of the pointer pointing to the data
2610 	 */
2611 	if (vdata_addr != NULL)
2612 		cfg_data = vdata_addr;
2613 
2614 	/*
2615 	 * just copy in the specified data, if no need
2616 	 * to verify the data or notify the associated
2617 	 * component
2618 	 */
2619 		if (get_group == nscd_true) {
2620 
2621 			gdesc = &_nscd_cfg_param_desc[desc->g_index];
2622 
2623 			rc = _nscd_cfg_copy_group_data_merge(
2624 				gdesc, &pdata, data, cfg_data,
2625 				desc->id.index, data);
2626 
2627 			if (rc != NSCD_SUCCESS) {
2628 				_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2629 				(me, "unable to copy group data <%s : %s>\n",
2630 				NSCD_STR_OR_GLOBAL(nswdb_name),
2631 				NSCD_STR_OR_NULL(param_name));
2632 
2633 				goto error_exit;
2634 			}
2635 
2636 			rc = _nscd_cfg_notify_s(gdesc, nswdb,
2637 				pdata, errorp);
2638 
2639 		} else
2640 			rc = _nscd_cfg_notify_s(desc, nswdb, data,
2641 				errorp);
2642 
2643 		if (rc != NSCD_SUCCESS) {
2644 
2645 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2646 			(me, "verifying/notifying  of new configuration "
2647 			"parameter <%s : %s> failed. %s\n",
2648 			NSCD_STR_OR_GLOBAL(nswdb_name),
2649 			param_name, (*errorp && (*errorp)->msg) ?
2650 			(*errorp)->msg : "");
2651 
2652 			goto error_exit;
2653 		}
2654 
2655 	/*
2656 	 * Move the new config into the config store
2657 	 */
2658 	rc = NSCD_CFG_SET_PARAM_FAILED;
2659 	if (_nscd_cfg_flag_is_set(desc->pflag,
2660 			NSCD_CFG_PFLAG_GROUP)) {
2661 		gi = _nscd_cfg_get_gi(pdata);
2662 		rc = _nscd_cfg_copy_group_data_in(gdesc, gi,
2663 			cfg_data, pdata);
2664 	} else {
2665 		/*
2666 		 * nscd_true asks _nscd_cfg_copy_param_data to
2667 		 * set addr of the vlen data in 'cfg_data' rather
2668 		 * than copying the data content
2669 		 */
2670 		if (pdata != NULL)
2671 			_nscd_cfg_free_vlen_data_group(gdesc,
2672 				pdata, in);
2673 
2674 		rc = _nscd_cfg_copy_param_data(desc,
2675 			cfg_data, data, in, nscd_true);
2676 	}
2677 
2678 	if (rc != NSCD_SUCCESS) {
2679 
2680 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2681 		(me, "unable to make new param data <%s : %s> current\n",
2682 		NSCD_STR_OR_GLOBAL(nswdb_name),
2683 		NSCD_STR_OR_NULL(param_name));
2684 	}
2685 
2686 	error_exit:
2687 
2688 	_nscd_cfg_unlock(lock);
2689 
2690 	return (rc);
2691 }
2692 
2693 nscd_rc_t
2694 _nscd_cfg_set_linked(
2695 	nscd_cfg_handle_t		*handle,
2696 	void				*data,
2697 	nscd_cfg_error_t		**errorp)
2698 {
2699 	char				*me = "_nscd_cfg_set_linked";
2700 	nscd_cfg_id_t			*nswdb;
2701 	nscd_cfg_handle_t		*hl;
2702 	nscd_cfg_param_desc_t		*desc;
2703 	char				*nswdb_name, *param_name, *dbl;
2704 	nscd_rc_t			rc = NSCD_SUCCESS;
2705 	nscd_cfg_nsw_spc_default_t	*spc;
2706 	int				i;
2707 	char				msg[NSCD_CFG_MAX_ERR_MSG_LEN];
2708 
2709 	if (handle == NULL) {
2710 		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2711 		(me, "handle is NULL\n");
2712 		return (NSCD_INVALID_ARGUMENT);
2713 	}
2714 
2715 	nswdb = handle->nswdb;
2716 	desc = (nscd_cfg_param_desc_t *)handle->desc;
2717 
2718 	/*
2719 	 * no need to do the special linking thing,
2720 	 * if a global param, or a group, or not a linked param
2721 	 */
2722 	if (nswdb == NULL || _nscd_cfg_flag_is_set(desc->pflag,
2723 			NSCD_CFG_PFLAG_GROUP) ||
2724 			_nscd_cfg_flag_is_not_set(desc->pflag,
2725 			NSCD_CFG_PFLAG_LINKED))
2726 		return (_nscd_cfg_set(handle, data, errorp));
2727 	else
2728 		nswdb_name = nswdb->name;
2729 	param_name = desc->id.name;
2730 
2731 	/*
2732 	 * if a param is linked to another, it can not be
2733 	 * changed directly
2734 	 */
2735 	for (i = 0; i < _nscd_cfg_num_link_default; i++) {
2736 
2737 		if (_nscd_cfg_nsw_link_default[i].data == NULL)
2738 			continue;
2739 
2740 		if (strcmp(_nscd_cfg_nsw_link_default[i].db,
2741 				nswdb_name) == 0 &&
2742 			_nscd_cfg_nsw_link_default[i].group_off ==
2743 				desc->g_offset &&
2744 			_nscd_cfg_nsw_link_default[i].param_off ==
2745 				desc->p_offset) {
2746 
2747 			rc = NSCD_CFG_READ_ONLY;
2748 
2749 			(void) snprintf(msg, sizeof (msg),
2750 gettext("vaule of \'%s\' not changeable, change that of \'%s\' instead"),
2751 				nswdb->name, "passwd");
2752 
2753 			if (errorp != NULL)
2754 				*errorp = _nscd_cfg_make_error(rc, msg);
2755 
2756 			_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
2757 			(me, "ERROR: %s\n", msg);
2758 
2759 			return (rc);
2760 		}
2761 	}
2762 
2763 	/*
2764 	 * if a param is linked from another, it should be verify
2765 	 * and changed first
2766 	 */
2767 	for (i = 0; i < _nscd_cfg_num_link_default; i++) {
2768 
2769 		if (_nscd_cfg_nsw_link_default[i].data == NULL)
2770 			continue;
2771 
2772 		spc = _nscd_cfg_nsw_link_default[i].data;
2773 
2774 		if (strcmp(spc->db, nswdb_name) == 0 &&
2775 			spc->group_off == desc->g_offset &&
2776 			spc->param_off == desc->p_offset) {
2777 
2778 			rc = _nscd_cfg_set(handle, data, errorp);
2779 			if (rc != NSCD_SUCCESS)
2780 				return (rc);
2781 			break;
2782 		}
2783 	}
2784 
2785 	/*
2786 	 * then change all those linked to the one that has been changed
2787 	 */
2788 	for (i = 0; i < _nscd_cfg_num_link_default; i++) {
2789 
2790 		if (_nscd_cfg_nsw_link_default[i].data == NULL)
2791 			continue;
2792 
2793 		spc = _nscd_cfg_nsw_link_default[i].data;
2794 
2795 		if (strcmp(spc->db, nswdb_name) == 0 &&
2796 			spc->group_off == desc->g_offset &&
2797 			spc->param_off == desc->p_offset &&
2798 			_nscd_cfg_nsw_link_default[i].group_off ==
2799 				desc->g_offset &&
2800 			_nscd_cfg_nsw_link_default[i].param_off ==
2801 				desc->p_offset) {
2802 
2803 			dbl = _nscd_cfg_nsw_link_default[i].db;
2804 
2805 			rc = _nscd_cfg_get_handle(param_name, dbl,
2806 				&hl, errorp);
2807 			if (rc != NSCD_SUCCESS)
2808 				return (rc);
2809 			rc = _nscd_cfg_set(hl, data, errorp);
2810 			_nscd_cfg_free_handle(hl);
2811 			if (rc != NSCD_SUCCESS)
2812 				return (rc);
2813 		}
2814 	}
2815 
2816 	return (_nscd_cfg_set(handle, data, errorp));
2817 }
2818 
2819 /*
2820  * Return a list of space-separated database names that
2821  * have at least one of the input sources appeared in the
2822  * configured nsswitch policy string of the databases.
2823  * The return string should be freed by the caller.
2824  *
2825  * For compat sources (compat_group and compat_passwd),
2826  * "group" will be returned, if the policy string for
2827  * compat_group contains one of the input sources. Same
2828  * for compat_passwd and passwd.
2829  */
2830 char *
2831 _nscd_srcs_in_db_nsw_policy(
2832 	int			num_src,
2833 	char			**srcs)
2834 {
2835 	uint8_t			i, j, n = 0, nc = 0;
2836 	uint8_t			compat_grp = 0, compat_pwd = 0;
2837 	uint8_t			*db;
2838 	uint8_t			*db_compat;
2839 	int			dlen = 0;
2840 	nscd_cfg_nsw_db_data_t	*dbcfg;
2841 	nscd_cfg_switch_t	*sw;
2842 	char			*outstr = NULL;
2843 	char			*dbname;
2844 
2845 	db = (uint8_t *)calloc(_nscd_cfg_num_nsw_db, sizeof (uint8_t));
2846 	if (db == NULL)
2847 		return (NULL);
2848 
2849 	db_compat = (uint8_t *)calloc(_nscd_cfg_num_nsw_db,
2850 		sizeof (uint8_t));
2851 	if (db_compat == NULL) {
2852 		free(db);
2853 		return (NULL);
2854 	}
2855 
2856 	for (i = 0; i < _nscd_cfg_num_nsw_db; i++) {
2857 
2858 		(void) rw_rdlock(&nscd_cfg_nsw_db_data_rwlock[i]);
2859 
2860 		dbcfg = &nscd_cfg_nsw_db_data_current[i];
2861 		sw = &dbcfg->sw;
2862 		if (sw->nsw_config_string == NULL)
2863 			continue;
2864 
2865 		dbname = _nscd_cfg_nsw_db[i].name;
2866 		for (j = 0; j < num_src; j++) {
2867 			if (strstr(sw->nsw_config_string, srcs[j]) !=
2868 				NULL) {
2869 				db[n++] = i;
2870 				dlen += strlen(dbname) + 1;
2871 			} else if (strcmp(sw->nsw_config_string,
2872 					"compat") == 0) {
2873 				if (strcmp(dbname, "passwd") == 0) {
2874 					compat_pwd = 1;
2875 					dlen += 7;
2876 				} else if (strcmp(dbname, "group") == 0) {
2877 					compat_grp = 1;
2878 					dlen += 6;
2879 				} else {
2880 					db_compat[nc++] = i;
2881 				dlen += strlen(dbname) + 1;
2882 
2883 				}
2884 			}
2885 		}
2886 		(void) rw_unlock(&nscd_cfg_nsw_db_data_rwlock[i]);
2887 	}
2888 
2889 	if (dlen != NULL)
2890 		outstr = (char *)calloc(1, dlen);
2891 	if (outstr == NULL) {
2892 		free(db_compat);
2893 		free(db);
2894 		return (NULL);
2895 	}
2896 
2897 	for (j = 0; j < n; j++) {
2898 		dbname = _nscd_cfg_nsw_db[db[j]].name;
2899 		if (strstr(dbname, "group_compat") != NULL) {
2900 			if (compat_grp == 1)
2901 				dbname = "group";
2902 			else
2903 				continue;
2904 		} else if (strstr(dbname, "passwd_compat") != NULL) {
2905 			if (compat_pwd == 1)
2906 				dbname = "passwd";
2907 			else
2908 				continue;
2909 		}
2910 
2911 		(void) strlcat(outstr, dbname, dlen);
2912 		(void) strlcat(outstr, ",", dlen);
2913 	}
2914 
2915 	for (j = 0; j < nc; j++) {
2916 		dbname = _nscd_cfg_nsw_db[db_compat[j]].name;
2917 		if (compat_pwd == 1) {
2918 			(void) strlcat(outstr, dbname, dlen);
2919 			(void) strlcat(outstr, " ", dlen);
2920 		}
2921 	}
2922 
2923 	free(db);
2924 	free(db_compat);
2925 	return (outstr);
2926 
2927 }
2928