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