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 <stdlib.h>
29#include <locale.h>
30#include <string.h>
31#include "nscd_config.h"
32#include "nscd_log.h"
33#include "nscd_switch.h"
34
35/*
36 * Configuration data for the nscd switch functions.
37 */
38nscd_cfg_global_switch_t	nscd_switch_cfg_g;
39nscd_cfg_switch_t		*nscd_switch_cfg;
40
41/*
42 * statistics of the nscd switch functions.
43 */
44nscd_cfg_stat_global_switch_t	nscd_switch_stats_g;
45nscd_cfg_stat_switch_t		*nscd_switch_stats;
46
47/*
48 * cookie is set up by the verify function for passing to
49 * the notify function
50 */
51typedef struct {
52	struct __nsw_switchconfig_v1	*cfg;
53	char				*cfgstr;
54} nsw_cfg_cookie_t;
55
56nscd_rc_t
57_nscd_alloc_switch_cfg()
58{
59	nscd_switch_cfg  = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_switch_t));
60	if (nscd_switch_cfg == NULL)
61		return (NSCD_NO_MEMORY);
62
63	return (NSCD_SUCCESS);
64}
65
66nscd_rc_t
67_nscd_alloc_switch_stats()
68{
69
70	nscd_switch_stats = calloc(NSCD_NUM_DB,
71		sizeof (nscd_cfg_stat_switch_t));
72	if (nscd_switch_stats == NULL)
73		return (NSCD_NO_MEMORY);
74
75	return (NSCD_SUCCESS);
76}
77
78/* ARGSUSED */
79nscd_rc_t
80_nscd_cfg_switch_notify(
81	void				*data,
82	struct nscd_cfg_param_desc	*pdesc,
83	nscd_cfg_id_t			*nswdb,
84	nscd_cfg_flag_t			dflag,
85	nscd_cfg_error_t		**errorp,
86	void				*cookie)
87{
88
89	void				*dp;
90	nscd_rc_t			rc;
91	nsw_cfg_cookie_t		*ck = (nsw_cfg_cookie_t *)cookie;
92
93	if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) ||
94		_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
95		/*
96		 * group data is received, copy in the
97		 * entire strcture
98		 */
99		if (_nscd_cfg_flag_is_set(pdesc->pflag,
100			NSCD_CFG_PFLAG_GLOBAL)) {
101			nscd_switch_cfg_g = *(nscd_cfg_global_switch_t *)data;
102		} else {
103			nscd_switch_cfg[nswdb->index] =
104				*(nscd_cfg_switch_t *)data;
105
106		}
107	} else {
108		/*
109		 * individual paramater is received: copy in the
110		 * parameter value except for nsw-config-string.
111		 */
112		if (_nscd_cfg_flag_is_set(pdesc->pflag,
113			NSCD_CFG_PFLAG_GLOBAL)) {
114			dp = (char *)&nscd_switch_cfg_g + pdesc->p_offset;
115			(void) memcpy(dp, data, pdesc->p_size);
116		} else {
117			dp = (char *)&nscd_switch_cfg[nswdb->index] +
118				pdesc->p_offset;
119			if (pdesc->p_offset !=
120				offsetof(nscd_cfg_switch_t, nsw_config_string))
121				(void) memcpy(dp, data, pdesc->p_size);
122		}
123	}
124
125	/*
126	 * cookie contains data for the switch policy config
127	 */
128	if (cookie != NULL) {
129		rc = _nscd_create_sw_struct(nswdb->index, -1, nswdb->name,
130			ck->cfgstr, ck->cfg, NULL);
131		if (rc != NSCD_SUCCESS) {
132			(void) __nsw_freeconfig_v1(ck->cfg);
133			free(ck);
134			return (rc);
135		}
136		free(ck);
137	}
138
139	if (_nscd_cfg_flag_is_not_set(dflag, NSCD_CFG_DFLAG_STATIC_DATA))
140		free(data);
141
142	return (NSCD_SUCCESS);
143}
144
145/* ARGSUSED */
146nscd_rc_t
147_nscd_cfg_switch_verify(
148	void				*data,
149	struct	nscd_cfg_param_desc	*pdesc,
150	nscd_cfg_id_t			*nswdb,
151	nscd_cfg_flag_t			dflag,
152	nscd_cfg_error_t		**errorp,
153	void				**cookie)
154{
155	char				*me = "_nscd_cfg_switch_verify";
156	nscd_cfg_switch_t		*cfg;
157	char				*nswcfgstr;
158	int				size;
159	struct __nsw_switchconfig_v1	*switchcfg = NULL;
160	enum __nsw_parse_err		err;
161	nsw_cfg_cookie_t		*ck;
162	char				buf[MAX_NSSWITCH_CONFIG_STRING_SZ];
163	char				msg[NSCD_CFG_MAX_ERR_MSG_LEN];
164
165	/*
166	 * global config data has nothing special to verify
167	 */
168	if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL))
169		return (NSCD_SUCCESS);
170
171	*cookie = NULL;
172
173	/*
174	 * switch policy string is the one to parse and verify
175	 */
176
177	if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) ||
178		_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
179
180		/* get it from the group data */
181		cfg = (nscd_cfg_switch_t *)data;
182		nswcfgstr = cfg->nsw_config_string;
183	} else {
184		/* not group, and not the switch policy string, return */
185		if (pdesc->p_offset != offsetof(nscd_cfg_switch_t,
186			nsw_config_string))
187		return (NSCD_SUCCESS);
188
189		/* the data itself is the string */
190		nswcfgstr = (char *)data;
191	}
192
193	/*
194	 * convert the string into struct __nsw_switchconfig_v1
195	 */
196	size = MAX_NSSWITCH_CONFIG_STRING_SZ;
197	if (strlcpy(buf, nswcfgstr, size) >= size) {
198
199		(void) snprintf(msg, sizeof (msg),
200	gettext("switch policy string too long (\"%s : %s\" > %d)"),
201			nswdb->name, nswcfgstr, size);
202
203		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
204		(me, "%s\n", msg);
205
206		if (*errorp)
207			*errorp = _nscd_cfg_make_error(
208				NSCD_CFG_SYNTAX_ERROR, msg);
209
210		return (NSCD_CFG_SYNTAX_ERROR);
211	}
212	switchcfg = _nsw_getoneconfig_v1(nswdb->name, buf, &err);
213	if (switchcfg == NULL) {
214
215		(void) snprintf(msg, sizeof (msg),
216		gettext("syntax error: switch policy string (%s : %s) rc = %d"),
217		nswdb->name, nswcfgstr, err);
218
219		_NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
220		(me, "%s\n", msg);
221
222		if (*errorp)
223			*errorp = _nscd_cfg_make_error(
224				NSCD_CFG_SYNTAX_ERROR, msg);
225
226		return (NSCD_CFG_SYNTAX_ERROR);
227	}
228
229	/* save the __nsw_switchconfig_v1 for the notify function */
230	ck = calloc(1, sizeof (nsw_cfg_cookie_t));
231	if (ck == NULL) {
232		(void) __nsw_freeconfig_v1(switchcfg);
233		return (NSCD_CFG_SYNTAX_ERROR);
234	}
235	ck->cfg = switchcfg;
236	ck->cfgstr = nswcfgstr;
237	*cookie = ck;
238
239	return (NSCD_SUCCESS);
240}
241
242/* ARGSUSED */
243nscd_rc_t
244_nscd_cfg_switch_get_stat(
245	void				**stat,
246	struct nscd_cfg_stat_desc	*sdesc,
247	nscd_cfg_id_t			*nswdb,
248	nscd_cfg_flag_t			*dflag,
249	void				(**free_stat)(void *stat),
250	nscd_cfg_error_t		**errorp)
251{
252
253	if (_nscd_cfg_flag_is_set(sdesc->sflag, NSCD_CFG_SFLAG_GLOBAL)) {
254		*stat = &NSCD_SW_STATS_G;
255	} else
256		*stat = &NSCD_SW_STATS(nswdb->index);
257
258	/* indicate the statistics are static, i.e., do not free */
259	*dflag = _nscd_cfg_flag_set(*dflag, NSCD_CFG_DFLAG_STATIC_DATA);
260
261	return (NSCD_SUCCESS);
262}
263