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