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 * 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 * 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 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 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