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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <netinet/in.h> 31 #include <netinet/inetutil.h> 32 #include <netinet/dhcp.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <ctype.h> 36 #include <dhcpmsg.h> 37 #include <stdio.h> 38 #include <sys/stat.h> 39 #include <libnvpair.h> 40 41 #include "defaults.h" 42 43 struct dhcp_default { 44 45 const char *df_name; /* parameter name */ 46 const char *df_default; /* default value */ 47 int df_min; /* min value if type DF_INTEGER */ 48 int df_max; /* max value if type DF_INTEGER */ 49 }; 50 51 /* 52 * note: keep in the same order as tunable parameter constants in defaults.h 53 */ 54 55 static struct dhcp_default defaults[] = { 56 57 { "RELEASE_ON_SIGTERM", "0", 0, 0 }, 58 { "IGNORE_FAILED_ARP", "1", 0, 0 }, 59 { "OFFER_WAIT", "3", 1, 20 }, 60 { "ARP_WAIT", "1000", 100, 4000 }, 61 { "CLIENT_ID", NULL, 0, 0 }, 62 { "PARAM_REQUEST_LIST", NULL, 0, 0 }, 63 { "REQUEST_HOSTNAME", "1", 0, 0 } 64 }; 65 66 /* 67 * df_build_cache(): builds the defaults nvlist cache 68 * 69 * input: void 70 * output: a pointer to an nvlist of the current defaults, or NULL on failure 71 */ 72 73 static nvlist_t * 74 df_build_cache(void) 75 { 76 char entry[1024]; 77 int i; 78 char *param, *value, *end; 79 FILE *fp; 80 nvlist_t *nvlist; 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 (; *param != '\0'; param++) 116 *param = toupper(*param); 117 118 if (nvlist_add_string(nvlist, &entry[i], value) != 0) { 119 dhcpmsg(MSG_WARNING, "cannot build default value cache;" 120 " using built-in defaults"); 121 nvlist_free(nvlist); 122 nvlist = NULL; 123 break; 124 } 125 } 126 127 (void) fclose(fp); 128 return (nvlist); 129 } 130 131 /* 132 * df_get_string(): gets the string value of a given user-tunable parameter 133 * 134 * input: const char *: the interface the parameter applies to 135 * unsigned int: the parameter number to look up 136 * output: const char *: the parameter's value, or default if not set 137 * (must be copied by caller to be kept) 138 * NOTE: df_get_string() is both used by functions outside this source 139 * file to retrieve strings from the defaults file, *and* 140 * internally by other df_get_*() functions. 141 */ 142 143 const char * 144 df_get_string(const char *if_name, unsigned int p) 145 { 146 char *value; 147 char param[256]; 148 struct stat statbuf; 149 static struct stat df_statbuf; 150 static boolean_t df_unavail_msg = B_FALSE; 151 static nvlist_t *df_nvlist = NULL; 152 153 if (p >= (sizeof (defaults) / sizeof (*defaults))) 154 return (NULL); 155 156 if (stat(DHCP_AGENT_DEFAULTS, &statbuf) != 0) { 157 if (!df_unavail_msg) { 158 dhcpmsg(MSG_WARNING, "cannot access %s; using " 159 "built-in defaults", DHCP_AGENT_DEFAULTS); 160 df_unavail_msg = B_TRUE; 161 } 162 return (defaults[p].df_default); 163 } 164 165 /* 166 * if our cached parameters are stale, rebuild. 167 */ 168 169 if (statbuf.st_mtime != df_statbuf.st_mtime || 170 statbuf.st_size != df_statbuf.st_size) { 171 df_statbuf = statbuf; 172 if (df_nvlist != NULL) 173 nvlist_free(df_nvlist); 174 df_nvlist = df_build_cache(); 175 } 176 177 (void) snprintf(param, sizeof (param), "%s.%s", if_name, 178 defaults[p].df_name); 179 180 /* 181 * first look for `if_name.param', then `param'. if neither 182 * has been set, use the built-in default. 183 */ 184 185 if (nvlist_lookup_string(df_nvlist, param, &value) == 0 || 186 nvlist_lookup_string(df_nvlist, defaults[p].df_name, &value) == 0) 187 return (value); 188 189 return (defaults[p].df_default); 190 } 191 192 /* 193 * df_get_octet(): gets the integer value of a given user-tunable parameter 194 * 195 * input: const char *: the interface the parameter applies to 196 * unsigned int: the parameter number to look up 197 * unsigned int *: the length of the returned value 198 * output: uchar_t *: a pointer to byte array (default value if not set) 199 * (must be copied by caller to be kept) 200 */ 201 202 uchar_t * 203 df_get_octet(const char *if_name, unsigned int p, unsigned int *len) 204 { 205 const char *value; 206 static uchar_t octet_value[256]; /* as big as defread() returns */ 207 208 if (p >= (sizeof (defaults) / sizeof (*defaults))) 209 return (NULL); 210 211 value = df_get_string(if_name, p); 212 if (value == NULL) 213 goto do_default; 214 215 if (strncasecmp("0x", value, 2) != 0) { 216 *len = strlen(value); /* no NUL */ 217 return ((uchar_t *)value); 218 } 219 220 /* skip past the 0x and convert the value to binary */ 221 value += 2; 222 *len = sizeof (octet_value); 223 if (hexascii_to_octet(value, strlen(value), octet_value, len) != 0) { 224 dhcpmsg(MSG_WARNING, "df_get_octet: cannot convert value " 225 "for parameter `%s', using default", defaults[p].df_name); 226 goto do_default; 227 } 228 return (octet_value); 229 230 do_default: 231 if (defaults[p].df_default == NULL) { 232 *len = 0; 233 return (NULL); 234 } 235 236 *len = strlen(defaults[p].df_default); /* no NUL */ 237 return ((uchar_t *)defaults[p].df_default); 238 } 239 240 /* 241 * df_get_int(): gets the integer value of a given user-tunable parameter 242 * 243 * input: const char *: the interface the parameter applies to 244 * unsigned int: the parameter number to look up 245 * output: int: the parameter's value, or default if not set 246 */ 247 248 int 249 df_get_int(const char *if_name, unsigned int p) 250 { 251 const char *value; 252 int value_int; 253 254 if (p >= (sizeof (defaults) / sizeof (*defaults))) 255 return (0); 256 257 value = df_get_string(if_name, p); 258 if (value == NULL || !isdigit(*value)) 259 goto failure; 260 261 value_int = atoi(value); 262 if (value_int > defaults[p].df_max || value_int < defaults[p].df_min) 263 goto failure; 264 265 return (value_int); 266 267 failure: 268 dhcpmsg(MSG_WARNING, "df_get_int: parameter `%s' is not between %d and " 269 "%d, defaulting to `%s'", defaults[p].df_name, defaults[p].df_min, 270 defaults[p].df_max, defaults[p].df_default); 271 return (atoi(defaults[p].df_default)); 272 } 273 274 /* 275 * df_get_bool(): gets the boolean value of a given user-tunable parameter 276 * 277 * input: const char *: the interface the parameter applies to 278 * unsigned int: the parameter number to look up 279 * output: boolean_t: B_TRUE if true, B_FALSE if false, default if not set 280 */ 281 282 boolean_t 283 df_get_bool(const char *if_name, unsigned int p) 284 { 285 const char *value; 286 287 if (p >= (sizeof (defaults) / sizeof (*defaults))) 288 return (0); 289 290 value = df_get_string(if_name, p); 291 if (value != NULL) { 292 293 if (strcasecmp(value, "true") == 0 || 294 strcasecmp(value, "yes") == 0 || strcmp(value, "1") == 0) 295 return (B_TRUE); 296 297 if (strcasecmp(value, "false") == 0 || 298 strcasecmp(value, "no") == 0 || strcmp(value, "0") == 0) 299 return (B_FALSE); 300 } 301 302 dhcpmsg(MSG_WARNING, "df_get_bool: parameter `%s' has invalid value " 303 "`%s', defaulting to `%s'", defaults[p].df_name, 304 value ? value : "NULL", defaults[p].df_default); 305 306 return ((atoi(defaults[p].df_default) == 0) ? B_FALSE : B_TRUE); 307 } 308