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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/types.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <dhcpmsg.h>
31 #include <stdio.h>
32 #include <sys/stat.h>
33 #include <libnvpair.h>
34
35 #include "common.h"
36 #include "defaults.h"
37
38 struct dhcp_default {
39
40 const char *df_name; /* parameter name */
41 const char *df_default; /* default value */
42 int df_min; /* min value if type DF_INTEGER */
43 int df_max; /* max value if type DF_INTEGER */
44 };
45
46 /*
47 * note: keep in the same order as tunable parameter constants in defaults.h
48 */
49
50 static struct dhcp_default defaults[] = {
51
52 { "RELEASE_ON_SIGTERM", "0", 0, 0 },
53 { "IGNORE_FAILED_ARP", "1", 0, -1 },
54 { "OFFER_WAIT", "3", 1, 20 },
55 { "ARP_WAIT", "1000", 0, -1 },
56 { "CLIENT_ID", NULL, 0, 0 },
57 { "PARAM_REQUEST_LIST", NULL, 0, 0 },
58 { "REQUEST_HOSTNAME", "1", 0, 0 },
59 { "DEBUG_LEVEL", "0", 0, 3 },
60 { "VERBOSE", "0", 0, 0 },
61 { "VERIFIED_LEASE_ONLY", "0", 0, 0 },
62 { "PARAM_IGNORE_LIST", NULL, 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 *
df_build_cache(void)73 df_build_cache(void)
74 {
75 char entry[1024];
76 int i;
77 char *param, *pastv6, *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 pastv6 = param = entry;
112 } else {
113 pastv6 = ++param;
114 if (strncasecmp(param, "v6.", 3) == 0)
115 pastv6 += 3;
116 }
117
118 for (defp = defaults;
119 (char *)defp < (char *)defaults + sizeof (defaults);
120 defp++) {
121 if (strcasecmp(pastv6, defp->df_name) == 0) {
122 if (defp->df_max == -1) {
123 dhcpmsg(MSG_WARNING, "parameter %s is "
124 "obsolete; ignored", defp->df_name);
125 }
126 break;
127 }
128 }
129
130 for (; *param != '\0'; param++)
131 *param = toupper(*param);
132
133 if (nvlist_add_string(nvlist, &entry[i], value) != 0) {
134 dhcpmsg(MSG_WARNING, "cannot build default value cache;"
135 " using built-in defaults");
136 nvlist_free(nvlist);
137 nvlist = NULL;
138 break;
139 }
140 }
141
142 (void) fclose(fp);
143 return (nvlist);
144 }
145
146 /*
147 * df_get_string(): gets the string value of a given user-tunable parameter
148 *
149 * input: const char *: the interface the parameter applies to
150 * boolean_t: B_TRUE for DHCPv6, B_FALSE for IPv4 DHCP
151 * uint_t: the parameter number to look up
152 * output: const char *: the parameter's value, or default if not set
153 * (must be copied by caller to be kept)
154 * NOTE: df_get_string() is both used by functions outside this source
155 * file to retrieve strings from the defaults file, *and*
156 * internally by other df_get_*() functions.
157 */
158
159 const char *
df_get_string(const char * if_name,boolean_t isv6,uint_t param)160 df_get_string(const char *if_name, boolean_t isv6, uint_t param)
161 {
162 char *value;
163 char paramstr[256];
164 char name[256];
165 struct stat statbuf;
166 static struct stat df_statbuf;
167 static boolean_t df_unavail_msg = B_FALSE;
168 static nvlist_t *df_nvlist = NULL;
169
170 if (param >= (sizeof (defaults) / sizeof (*defaults)))
171 return (NULL);
172
173 if (stat(DHCP_AGENT_DEFAULTS, &statbuf) != 0) {
174 if (!df_unavail_msg) {
175 dhcpmsg(MSG_WARNING, "cannot access %s; using "
176 "built-in defaults", DHCP_AGENT_DEFAULTS);
177 df_unavail_msg = B_TRUE;
178 }
179 return (defaults[param].df_default);
180 }
181
182 /*
183 * if our cached parameters are stale, rebuild.
184 */
185
186 if (statbuf.st_mtime != df_statbuf.st_mtime ||
187 statbuf.st_size != df_statbuf.st_size) {
188 df_statbuf = statbuf;
189 if (df_nvlist != NULL)
190 nvlist_free(df_nvlist);
191 df_nvlist = df_build_cache();
192 }
193
194 if (isv6) {
195 (void) snprintf(name, sizeof (name), ".V6.%s",
196 defaults[param].df_name);
197 (void) snprintf(paramstr, sizeof (paramstr), "%s%s", if_name,
198 name);
199 } else {
200 (void) strlcpy(name, defaults[param].df_name, sizeof (name));
201 (void) snprintf(paramstr, sizeof (paramstr), "%s.%s", if_name,
202 name);
203 }
204
205 /*
206 * first look for `if_name.[v6.]param', then `[v6.]param'. if neither
207 * has been set, use the built-in default.
208 */
209
210 if (nvlist_lookup_string(df_nvlist, paramstr, &value) == 0 ||
211 nvlist_lookup_string(df_nvlist, name, &value) == 0)
212 return (value);
213
214 return (defaults[param].df_default);
215 }
216
217 /*
218 * df_get_int(): gets the integer value of a given user-tunable parameter
219 *
220 * input: const char *: the interface the parameter applies to
221 * boolean_t: B_TRUE for DHCPv6, B_FALSE for IPv4 DHCP
222 * uint_t: the parameter number to look up
223 * output: int: the parameter's value, or default if not set
224 */
225
226 int
df_get_int(const char * if_name,boolean_t isv6,uint_t param)227 df_get_int(const char *if_name, boolean_t isv6, uint_t param)
228 {
229 const char *value;
230 int value_int;
231
232 if (param >= (sizeof (defaults) / sizeof (*defaults)))
233 return (0);
234
235 value = df_get_string(if_name, isv6, param);
236 if (value == NULL || !isdigit(*value))
237 goto failure;
238
239 value_int = atoi(value);
240 if (value_int > defaults[param].df_max ||
241 value_int < defaults[param].df_min)
242 goto failure;
243
244 return (value_int);
245
246 failure:
247 dhcpmsg(MSG_WARNING, "df_get_int: parameter `%s' is not between %d and "
248 "%d, defaulting to `%s'", defaults[param].df_name,
249 defaults[param].df_min, defaults[param].df_max,
250 defaults[param].df_default);
251 return (atoi(defaults[param].df_default));
252 }
253
254 /*
255 * df_get_bool(): gets the boolean value of a given user-tunable parameter
256 *
257 * input: const char *: the interface the parameter applies to
258 * boolean_t: B_TRUE for DHCPv6, B_FALSE for IPv4 DHCP
259 * uint_t: the parameter number to look up
260 * output: boolean_t: B_TRUE if true, B_FALSE if false, default if not set
261 */
262
263 boolean_t
df_get_bool(const char * if_name,boolean_t isv6,uint_t param)264 df_get_bool(const char *if_name, boolean_t isv6, uint_t param)
265 {
266 const char *value;
267
268 if (param >= (sizeof (defaults) / sizeof (*defaults)))
269 return (0);
270
271 value = df_get_string(if_name, isv6, param);
272 if (value != NULL) {
273
274 if (strcasecmp(value, "true") == 0 ||
275 strcasecmp(value, "yes") == 0 || strcmp(value, "1") == 0)
276 return (B_TRUE);
277
278 if (strcasecmp(value, "false") == 0 ||
279 strcasecmp(value, "no") == 0 || strcmp(value, "0") == 0)
280 return (B_FALSE);
281 }
282
283 dhcpmsg(MSG_WARNING, "df_get_bool: parameter `%s' has invalid value "
284 "`%s', defaulting to `%s'", defaults[param].df_name,
285 value != NULL ? value : "NULL", defaults[param].df_default);
286
287 return ((atoi(defaults[param].df_default) == 0) ? B_FALSE : B_TRUE);
288 }
289