xref: /illumos-gate/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.c (revision 60a3f738d56f92ae8b80e4b62a2331c6e1f2311f)
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 <sys/types.h>
29 #include <netinet/in.h>
30 #include <netinet/inetutil.h>
31 #include <netinet/dhcp.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <dhcpmsg.h>
36 #include <stdio.h>
37 #include <sys/stat.h>
38 #include <libnvpair.h>
39 
40 #include "defaults.h"
41 
42 struct dhcp_default {
43 
44 	const char	*df_name;	/* parameter name */
45 	const char	*df_default;	/* default value */
46 	int		df_min;		/* min value if type DF_INTEGER */
47 	int		df_max;		/* max value if type DF_INTEGER */
48 };
49 
50 /*
51  * note: keep in the same order as tunable parameter constants in defaults.h
52  */
53 
54 static struct dhcp_default defaults[] = {
55 
56 	{ "RELEASE_ON_SIGTERM",  "0",	 0,   0	  },
57 	{ "IGNORE_FAILED_ARP",	 "1",	 0,   -1  },
58 	{ "OFFER_WAIT",		 "3",	 1,   20  },
59 	{ "ARP_WAIT",		 "1000", 0,   -1  },
60 	{ "CLIENT_ID",		 NULL,	 0,   0	  },
61 	{ "PARAM_REQUEST_LIST",  NULL,	 0,   0    },
62 	{ "REQUEST_HOSTNAME",	 "1",	 0,   0	  }
63 };
64 
65 /*
66  * df_build_cache(): builds the defaults nvlist cache
67  *
68  *   input: void
69  *  output: a pointer to an nvlist of the current defaults, or NULL on failure
70  */
71 
72 static nvlist_t *
73 df_build_cache(void)
74 {
75 	char		entry[1024];
76 	int		i;
77 	char		*param, *value, *end;
78 	FILE		*fp;
79 	nvlist_t 	*nvlist;
80 	struct dhcp_default *defp;
81 
82 	if ((fp = fopen(DHCP_AGENT_DEFAULTS, "r")) == NULL)
83 		return (NULL);
84 
85 	if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
86 		dhcpmsg(MSG_WARNING, "cannot build default value cache; "
87 		    "using built-in defaults");
88 		(void) fclose(fp);
89 		return (NULL);
90 	}
91 
92 	while (fgets(entry, sizeof (entry), fp) != NULL) {
93 		for (i = 0; entry[i] == ' '; i++)
94 			;
95 
96 		end = strrchr(entry, '\n');
97 		value = strchr(entry, '=');
98 		if (end == NULL || value == NULL || entry[i] == '#')
99 			continue;
100 
101 		*end = '\0';
102 		*value++ = '\0';
103 
104 		/*
105 		 * to be compatible with the old defread()-based code
106 		 * which ignored case, store the parameters (except for the
107 		 * leading interface name) in upper case.
108 		 */
109 
110 		if ((param = strchr(entry, '.')) == NULL)
111 			param = entry;
112 		else
113 			param++;
114 
115 		for (defp = defaults;
116 		    (char *)defp < (char *)defaults + sizeof (defaults);
117 		    defp++) {
118 			if (strcasecmp(param, defp->df_name) == 0) {
119 				if (defp->df_max == -1) {
120 					dhcpmsg(MSG_WARNING, "parameter %s is "
121 					    "obsolete; ignored", defp->df_name);
122 				}
123 				break;
124 			}
125 		}
126 
127 		for (; *param != '\0'; param++)
128 			*param = toupper(*param);
129 
130 		if (nvlist_add_string(nvlist, &entry[i], value) != 0) {
131 			dhcpmsg(MSG_WARNING, "cannot build default value cache;"
132 			    " using built-in defaults");
133 			nvlist_free(nvlist);
134 			nvlist = NULL;
135 			break;
136 		}
137 	}
138 
139 	(void) fclose(fp);
140 	return (nvlist);
141 }
142 
143 /*
144  * df_get_string(): gets the string value of a given user-tunable parameter
145  *
146  *   input: const char *: the interface the parameter applies to
147  *	    unsigned int: the parameter number to look up
148  *  output: const char *: the parameter's value, or default if not set
149  *			  (must be copied by caller to be kept)
150  *    NOTE: df_get_string() is both used by functions outside this source
151  *	    file to retrieve strings from the defaults file, *and*
152  *	    internally by other df_get_*() functions.
153  */
154 
155 const char *
156 df_get_string(const char *if_name, unsigned int p)
157 {
158 	char			*value;
159 	char			param[256];
160 	struct stat		statbuf;
161 	static struct stat	df_statbuf;
162 	static boolean_t	df_unavail_msg = B_FALSE;
163 	static nvlist_t		*df_nvlist = NULL;
164 
165 	if (p >= (sizeof (defaults) / sizeof (*defaults)))
166 		return (NULL);
167 
168 	if (stat(DHCP_AGENT_DEFAULTS, &statbuf) != 0) {
169 		if (!df_unavail_msg) {
170 			dhcpmsg(MSG_WARNING, "cannot access %s; using "
171 			    "built-in defaults", DHCP_AGENT_DEFAULTS);
172 			df_unavail_msg = B_TRUE;
173 		}
174 		return (defaults[p].df_default);
175 	}
176 
177 	/*
178 	 * if our cached parameters are stale, rebuild.
179 	 */
180 
181 	if (statbuf.st_mtime != df_statbuf.st_mtime ||
182 	    statbuf.st_size != df_statbuf.st_size) {
183 		df_statbuf = statbuf;
184 		if (df_nvlist != NULL)
185 			nvlist_free(df_nvlist);
186 		df_nvlist = df_build_cache();
187 	}
188 
189 	(void) snprintf(param, sizeof (param), "%s.%s", if_name,
190 	    defaults[p].df_name);
191 
192 	/*
193 	 * first look for `if_name.param', then `param'.  if neither
194 	 * has been set, use the built-in default.
195 	 */
196 
197 	if (nvlist_lookup_string(df_nvlist, param, &value) == 0 ||
198 	    nvlist_lookup_string(df_nvlist, defaults[p].df_name, &value) == 0)
199 		return (value);
200 
201 	return (defaults[p].df_default);
202 }
203 
204 /*
205  * df_get_octet(): gets the integer value of a given user-tunable parameter
206  *
207  *   input: const char *: the interface the parameter applies to
208  *	    unsigned int: the parameter number to look up
209  *	    unsigned int *: the length of the returned value
210  *  output: uchar_t *: a pointer to byte array (default value if not set)
211  *		       (must be copied by caller to be kept)
212  */
213 
214 uchar_t *
215 df_get_octet(const char *if_name, unsigned int p, unsigned int *len)
216 {
217 	const char	*value;
218 	static uchar_t	octet_value[256]; /* as big as defread() returns */
219 
220 	if (p >= (sizeof (defaults) / sizeof (*defaults)))
221 		return (NULL);
222 
223 	value = df_get_string(if_name, p);
224 	if (value == NULL)
225 		goto do_default;
226 
227 	if (strncasecmp("0x", value, 2) != 0) {
228 		*len = strlen(value);			/* no NUL */
229 		return ((uchar_t *)value);
230 	}
231 
232 	/* skip past the 0x and convert the value to binary */
233 	value += 2;
234 	*len = sizeof (octet_value);
235 	if (hexascii_to_octet(value, strlen(value), octet_value, len) != 0) {
236 		dhcpmsg(MSG_WARNING, "df_get_octet: cannot convert value "
237 		    "for parameter `%s', using default", defaults[p].df_name);
238 		goto do_default;
239 	}
240 	return (octet_value);
241 
242 do_default:
243 	if (defaults[p].df_default == NULL) {
244 		*len = 0;
245 		return (NULL);
246 	}
247 
248 	*len = strlen(defaults[p].df_default);		/* no NUL */
249 	return ((uchar_t *)defaults[p].df_default);
250 }
251 
252 /*
253  * df_get_int(): gets the integer value of a given user-tunable parameter
254  *
255  *   input: const char *: the interface the parameter applies to
256  *	    unsigned int: the parameter number to look up
257  *  output: int: the parameter's value, or default if not set
258  */
259 
260 int
261 df_get_int(const char *if_name, unsigned int p)
262 {
263 	const char	*value;
264 	int		value_int;
265 
266 	if (p >= (sizeof (defaults) / sizeof (*defaults)))
267 		return (0);
268 
269 	value = df_get_string(if_name, p);
270 	if (value == NULL || !isdigit(*value))
271 		goto failure;
272 
273 	value_int = atoi(value);
274 	if (value_int > defaults[p].df_max || value_int < defaults[p].df_min)
275 		goto failure;
276 
277 	return (value_int);
278 
279 failure:
280 	dhcpmsg(MSG_WARNING, "df_get_int: parameter `%s' is not between %d and "
281 	    "%d, defaulting to `%s'", defaults[p].df_name, defaults[p].df_min,
282 	    defaults[p].df_max, defaults[p].df_default);
283 	return (atoi(defaults[p].df_default));
284 }
285 
286 /*
287  * df_get_bool(): gets the boolean value of a given user-tunable parameter
288  *
289  *   input: const char *: the interface the parameter applies to
290  *	    unsigned int: the parameter number to look up
291  *  output: boolean_t: B_TRUE if true, B_FALSE if false, default if not set
292  */
293 
294 boolean_t
295 df_get_bool(const char *if_name, unsigned int p)
296 {
297 	const char	*value;
298 
299 	if (p >= (sizeof (defaults) / sizeof (*defaults)))
300 		return (0);
301 
302 	value = df_get_string(if_name, p);
303 	if (value != NULL) {
304 
305 		if (strcasecmp(value, "true") == 0 ||
306 		    strcasecmp(value, "yes") == 0 || strcmp(value, "1") == 0)
307 			return (B_TRUE);
308 
309 		if (strcasecmp(value, "false") == 0 ||
310 		    strcasecmp(value, "no") == 0 || strcmp(value, "0") == 0)
311 			return (B_FALSE);
312 	}
313 
314 	dhcpmsg(MSG_WARNING, "df_get_bool: parameter `%s' has invalid value "
315 	    "`%s', defaulting to `%s'", defaults[p].df_name,
316 	    value ? value : "NULL", defaults[p].df_default);
317 
318 	return ((atoi(defaults[p].df_default) == 0) ? B_FALSE : B_TRUE);
319 }
320