1*cb5caa98Sdjl /* 2*cb5caa98Sdjl * CDDL HEADER START 3*cb5caa98Sdjl * 4*cb5caa98Sdjl * The contents of this file are subject to the terms of the 5*cb5caa98Sdjl * Common Development and Distribution License (the "License"). 6*cb5caa98Sdjl * You may not use this file except in compliance with the License. 7*cb5caa98Sdjl * 8*cb5caa98Sdjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*cb5caa98Sdjl * or http://www.opensolaris.org/os/licensing. 10*cb5caa98Sdjl * See the License for the specific language governing permissions 11*cb5caa98Sdjl * and limitations under the License. 12*cb5caa98Sdjl * 13*cb5caa98Sdjl * When distributing Covered Code, include this CDDL HEADER in each 14*cb5caa98Sdjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*cb5caa98Sdjl * If applicable, add the following below this CDDL HEADER, with the 16*cb5caa98Sdjl * fields enclosed by brackets "[]" replaced with your own identifying 17*cb5caa98Sdjl * information: Portions Copyright [yyyy] [name of copyright owner] 18*cb5caa98Sdjl * 19*cb5caa98Sdjl * CDDL HEADER END 20*cb5caa98Sdjl */ 21*cb5caa98Sdjl /* 22*cb5caa98Sdjl * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*cb5caa98Sdjl * Use is subject to license terms. 24*cb5caa98Sdjl */ 25*cb5caa98Sdjl 26*cb5caa98Sdjl #pragma ident "%Z%%M% %I% %E% SMI" 27*cb5caa98Sdjl 28*cb5caa98Sdjl #include <stdlib.h> 29*cb5caa98Sdjl #include <limits.h> 30*cb5caa98Sdjl #include <string.h> 31*cb5caa98Sdjl #include <ctype.h> 32*cb5caa98Sdjl 33*cb5caa98Sdjl #define __NSS_PRIVATE_INTERFACE 34*cb5caa98Sdjl #include "nsswitch_priv.h" 35*cb5caa98Sdjl #undef __NSS_PRIVATE_INTERFACE 36*cb5caa98Sdjl 37*cb5caa98Sdjl #define islabel(c) (isalnum(c) || (c) == '_') 38*cb5caa98Sdjl 39*cb5caa98Sdjl /* 40*cb5caa98Sdjl * The _nsw_getoneconfig_v1() in this file parses the switch policy 41*cb5caa98Sdjl * configuration for a switch database, e.g., 42*cb5caa98Sdjl * 43*cb5caa98Sdjl * hosts: nis [NOTFOUND=return] files 44*cb5caa98Sdjl * or 45*cb5caa98Sdjl * printers: user files nis 46*cb5caa98Sdjl */ 47*cb5caa98Sdjl 48*cb5caa98Sdjl /* 49*cb5caa98Sdjl * Local routines 50*cb5caa98Sdjl */ 51*cb5caa98Sdjl static char *skip(char **, char); 52*cb5caa98Sdjl static char *labelskip(char *); 53*cb5caa98Sdjl static char *spaceskip(char *); 54*cb5caa98Sdjl static void freeconf_v1(struct __nsw_switchconfig_v1 *); 55*cb5caa98Sdjl static int alldigits(char *); 56*cb5caa98Sdjl 57*cb5caa98Sdjl /* 58*cb5caa98Sdjl * 59*cb5caa98Sdjl * With the "lookup control" feature, the default criteria for NIS, NIS+, 60*cb5caa98Sdjl * and any new services (e.g. ldap) will be: 61*cb5caa98Sdjl * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=forever] 62*cb5caa98Sdjl * 63*cb5caa98Sdjl * For backward compat, NIS via NIS server in DNS forwarding mode will be: 64*cb5caa98Sdjl * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=continue] 65*cb5caa98Sdjl * 66*cb5caa98Sdjl * And also for backward compat, the default criteria for DNS will be: 67*cb5caa98Sdjl * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=continue] 68*cb5caa98Sdjl */ 69*cb5caa98Sdjl 70*cb5caa98Sdjl 71*cb5caa98Sdjl 72*cb5caa98Sdjl /* 73*cb5caa98Sdjl * The BIND resolver normally will retry several times on server non-response. 74*cb5caa98Sdjl * But now with the "lookup control" feature, we don't want the resolver doing 75*cb5caa98Sdjl * many retries, rather we want it to return control (reasonably) quickly back 76*cb5caa98Sdjl * to the switch engine. However, when TRYAGAIN=N or TRYAGAIN=forever is 77*cb5caa98Sdjl * not explicitly set by the admin in the conf file, we want the old "resolver 78*cb5caa98Sdjl * retry a few times" rather than no retries at all. 79*cb5caa98Sdjl */ 80*cb5caa98Sdjl static int dns_tryagain_retry = 3; 81*cb5caa98Sdjl 82*cb5caa98Sdjl /* 83*cb5caa98Sdjl * For backward compat (pre "lookup control"), the dns default behavior is 84*cb5caa98Sdjl * soft lookup. 85*cb5caa98Sdjl */ 86*cb5caa98Sdjl static void 87*cb5caa98Sdjl set_dns_default_lkp(struct __nsw_lookup_v1 *lkp) 88*cb5caa98Sdjl { 89*cb5caa98Sdjl if (strcasecmp(lkp->service_name, "dns") == 0) { 90*cb5caa98Sdjl lkp->actions[__NSW_TRYAGAIN] = 91*cb5caa98Sdjl __NSW_TRYAGAIN_NTIMES; 92*cb5caa98Sdjl lkp->max_retries = dns_tryagain_retry; 93*cb5caa98Sdjl } 94*cb5caa98Sdjl } 95*cb5caa98Sdjl 96*cb5caa98Sdjl static void 97*cb5caa98Sdjl freeconf_v1(struct __nsw_switchconfig_v1 *cfp) 98*cb5caa98Sdjl { 99*cb5caa98Sdjl if (cfp) { 100*cb5caa98Sdjl if (cfp->dbase) 101*cb5caa98Sdjl free(cfp->dbase); 102*cb5caa98Sdjl if (cfp->lookups) { 103*cb5caa98Sdjl struct __nsw_lookup_v1 *nex, *cur; 104*cb5caa98Sdjl for (cur = cfp->lookups; cur; cur = nex) { 105*cb5caa98Sdjl free(cur->service_name); 106*cb5caa98Sdjl nex = cur->next; 107*cb5caa98Sdjl free(cur); 108*cb5caa98Sdjl } 109*cb5caa98Sdjl } 110*cb5caa98Sdjl free(cfp); 111*cb5caa98Sdjl } 112*cb5caa98Sdjl } 113*cb5caa98Sdjl 114*cb5caa98Sdjl /* give the next non-alpha character */ 115*cb5caa98Sdjl static char * 116*cb5caa98Sdjl labelskip(char *cur) 117*cb5caa98Sdjl { 118*cb5caa98Sdjl char *p = cur; 119*cb5caa98Sdjl while (islabel(*p)) 120*cb5caa98Sdjl ++p; 121*cb5caa98Sdjl return (p); 122*cb5caa98Sdjl } 123*cb5caa98Sdjl 124*cb5caa98Sdjl /* give the next non-space character */ 125*cb5caa98Sdjl static char * 126*cb5caa98Sdjl spaceskip(char *cur) 127*cb5caa98Sdjl { 128*cb5caa98Sdjl char *p = cur; 129*cb5caa98Sdjl while (*p == ' ' || *p == '\t') 130*cb5caa98Sdjl ++p; 131*cb5caa98Sdjl return (p); 132*cb5caa98Sdjl } 133*cb5caa98Sdjl 134*cb5caa98Sdjl /* 135*cb5caa98Sdjl * terminate the *cur pointed string by null only if it is 136*cb5caa98Sdjl * followed by "key" surrounded by zero or more spaces and 137*cb5caa98Sdjl * return value is the same as the original *cur pointer and 138*cb5caa98Sdjl * *cur pointer is advanced to the first non {space, key} char 139*cb5caa98Sdjl * followed by the key. Otherwise, return NULL and keep 140*cb5caa98Sdjl * *cur unchanged. 141*cb5caa98Sdjl */ 142*cb5caa98Sdjl static char * 143*cb5caa98Sdjl skip(char **cur, char key) 144*cb5caa98Sdjl { 145*cb5caa98Sdjl char *p, *tmp; 146*cb5caa98Sdjl char *q = *cur; 147*cb5caa98Sdjl int found, tmpfound; 148*cb5caa98Sdjl 149*cb5caa98Sdjl tmp = labelskip(*cur); 150*cb5caa98Sdjl p = tmp; 151*cb5caa98Sdjl found = (*p == key); 152*cb5caa98Sdjl if (found) { 153*cb5caa98Sdjl *p++ = '\0'; /* overwrite the key */ 154*cb5caa98Sdjl p = spaceskip(p); 155*cb5caa98Sdjl } else { 156*cb5caa98Sdjl while (*p == ' ' || *p == '\t') { 157*cb5caa98Sdjl tmpfound = (*++p == key); 158*cb5caa98Sdjl if (tmpfound) { 159*cb5caa98Sdjl found = tmpfound; 160*cb5caa98Sdjl /* null terminate the return token */ 161*cb5caa98Sdjl *tmp = '\0'; 162*cb5caa98Sdjl p++; /* skip the key */ 163*cb5caa98Sdjl } 164*cb5caa98Sdjl } 165*cb5caa98Sdjl } 166*cb5caa98Sdjl if (!found) 167*cb5caa98Sdjl return (NULL); /* *cur unchanged */ 168*cb5caa98Sdjl *cur = p; 169*cb5caa98Sdjl return (q); 170*cb5caa98Sdjl } 171*cb5caa98Sdjl 172*cb5caa98Sdjl /* Return 1 if the string contains all digits, else return 0. */ 173*cb5caa98Sdjl static int 174*cb5caa98Sdjl alldigits(char *s) 175*cb5caa98Sdjl { 176*cb5caa98Sdjl for (; *s; s++) 177*cb5caa98Sdjl if (!isdigit(*s)) 178*cb5caa98Sdjl return (0); 179*cb5caa98Sdjl return (1); 180*cb5caa98Sdjl } 181*cb5caa98Sdjl 182*cb5caa98Sdjl struct __nsw_switchconfig_v1 * 183*cb5caa98Sdjl _nsw_getoneconfig_v1(const char *name, char *linep, enum __nsw_parse_err *errp) 184*cb5caa98Sdjl /* linep Nota Bene: not const char * */ 185*cb5caa98Sdjl /* errp Meanings are abused a bit */ 186*cb5caa98Sdjl { 187*cb5caa98Sdjl struct __nsw_switchconfig_v1 *cfp; 188*cb5caa98Sdjl struct __nsw_lookup_v1 *lkp, **lkq; 189*cb5caa98Sdjl int end_crit; 190*cb5caa98Sdjl action_t act; 191*cb5caa98Sdjl char *p, *tokenp; 192*cb5caa98Sdjl 193*cb5caa98Sdjl *errp = __NSW_CONF_PARSE_SUCCESS; 194*cb5caa98Sdjl 195*cb5caa98Sdjl if ((cfp = calloc(1, sizeof (struct __nsw_switchconfig_v1))) 196*cb5caa98Sdjl == NULL) { 197*cb5caa98Sdjl *errp = __NSW_CONF_PARSE_SYSERR; 198*cb5caa98Sdjl return (NULL); 199*cb5caa98Sdjl } 200*cb5caa98Sdjl cfp->dbase = strdup(name); 201*cb5caa98Sdjl lkq = &cfp->lookups; 202*cb5caa98Sdjl 203*cb5caa98Sdjl /* linep points to a naming service name */ 204*cb5caa98Sdjl for (;;) { 205*cb5caa98Sdjl int i; 206*cb5caa98Sdjl 207*cb5caa98Sdjl /* white space following the last service */ 208*cb5caa98Sdjl if (*linep == '\0' || *linep == '\n') { 209*cb5caa98Sdjl return (cfp); 210*cb5caa98Sdjl } 211*cb5caa98Sdjl if ((lkp = calloc(1, sizeof (struct __nsw_lookup_v1))) 212*cb5caa98Sdjl == NULL) { 213*cb5caa98Sdjl *errp = __NSW_CONF_PARSE_SYSERR; 214*cb5caa98Sdjl freeconf_v1(cfp); 215*cb5caa98Sdjl return (NULL); 216*cb5caa98Sdjl } 217*cb5caa98Sdjl 218*cb5caa98Sdjl *lkq = lkp; 219*cb5caa98Sdjl lkq = &lkp->next; 220*cb5caa98Sdjl 221*cb5caa98Sdjl for (i = 0; i < __NSW_STD_ERRS_V1; i++) 222*cb5caa98Sdjl if (i == __NSW_SUCCESS) 223*cb5caa98Sdjl lkp->actions[i] = __NSW_RETURN; 224*cb5caa98Sdjl else if (i == __NSW_TRYAGAIN) 225*cb5caa98Sdjl lkp->actions[i] = __NSW_TRYAGAIN_FOREVER; 226*cb5caa98Sdjl else 227*cb5caa98Sdjl lkp->actions[i] = __NSW_CONTINUE; 228*cb5caa98Sdjl 229*cb5caa98Sdjl /* get criteria for the naming service */ 230*cb5caa98Sdjl if (tokenp = skip(&linep, '[')) { /* got criteria */ 231*cb5caa98Sdjl 232*cb5caa98Sdjl /* premature end, illegal char following [ */ 233*cb5caa98Sdjl if (!islabel(*linep)) 234*cb5caa98Sdjl goto barf_line; 235*cb5caa98Sdjl lkp->service_name = strdup(tokenp); 236*cb5caa98Sdjl cfp->num_lookups++; 237*cb5caa98Sdjl 238*cb5caa98Sdjl set_dns_default_lkp(lkp); 239*cb5caa98Sdjl 240*cb5caa98Sdjl end_crit = 0; 241*cb5caa98Sdjl 242*cb5caa98Sdjl /* linep points to a switch_err */ 243*cb5caa98Sdjl for (;;) { 244*cb5caa98Sdjl int ntimes = 0; /* try again max N times */ 245*cb5caa98Sdjl int dns_continue = 0; 246*cb5caa98Sdjl 247*cb5caa98Sdjl if ((tokenp = skip(&linep, '=')) == NULL) { 248*cb5caa98Sdjl goto barf_line; 249*cb5caa98Sdjl } 250*cb5caa98Sdjl 251*cb5caa98Sdjl /* premature end, ill char following = */ 252*cb5caa98Sdjl if (!islabel(*linep)) 253*cb5caa98Sdjl goto barf_line; 254*cb5caa98Sdjl 255*cb5caa98Sdjl /* linep points to the string following '=' */ 256*cb5caa98Sdjl p = labelskip(linep); 257*cb5caa98Sdjl if (*p == ']') 258*cb5caa98Sdjl end_crit = 1; 259*cb5caa98Sdjl else if (*p != ' ' && *p != '\t') 260*cb5caa98Sdjl goto barf_line; 261*cb5caa98Sdjl *p++ = '\0'; /* null terminate linep */ 262*cb5caa98Sdjl p = spaceskip(p); 263*cb5caa98Sdjl if (!end_crit) { 264*cb5caa98Sdjl if (*p == ']') { 265*cb5caa98Sdjl end_crit = 1; 266*cb5caa98Sdjl *p++ = '\0'; 267*cb5caa98Sdjl } else if (*p == '\0' || *p == '\n') { 268*cb5caa98Sdjl return (cfp); 269*cb5caa98Sdjl } else if (!islabel(*p)) 270*cb5caa98Sdjl /* p better be the next switch_err */ 271*cb5caa98Sdjl goto barf_line; 272*cb5caa98Sdjl } 273*cb5caa98Sdjl if (strcasecmp(linep, __NSW_STR_RETURN) == 0) 274*cb5caa98Sdjl act = __NSW_RETURN; 275*cb5caa98Sdjl else if (strcasecmp(linep, 276*cb5caa98Sdjl __NSW_STR_CONTINUE) == 0) { 277*cb5caa98Sdjl if (strcasecmp(lkp->service_name, 278*cb5caa98Sdjl "dns") == 0 && 279*cb5caa98Sdjl strcasecmp(tokenp, 280*cb5caa98Sdjl __NSW_STR_TRYAGAIN) 281*cb5caa98Sdjl == 0) { 282*cb5caa98Sdjl /* 283*cb5caa98Sdjl * Add one more condition 284*cb5caa98Sdjl * so it retries only if it's 285*cb5caa98Sdjl * "dns [TRYAGAIN=continue]" 286*cb5caa98Sdjl */ 287*cb5caa98Sdjl dns_continue = 1; 288*cb5caa98Sdjl act = __NSW_TRYAGAIN_NTIMES; 289*cb5caa98Sdjl } else 290*cb5caa98Sdjl act = __NSW_CONTINUE; 291*cb5caa98Sdjl } else if (strcasecmp(linep, 292*cb5caa98Sdjl __NSW_STR_FOREVER) == 0) 293*cb5caa98Sdjl act = __NSW_TRYAGAIN_FOREVER; 294*cb5caa98Sdjl else if (alldigits(linep)) { 295*cb5caa98Sdjl act = __NSW_TRYAGAIN_NTIMES; 296*cb5caa98Sdjl ntimes = atoi(linep); 297*cb5caa98Sdjl if (ntimes < 0 || ntimes > INT_MAX) 298*cb5caa98Sdjl ntimes = 0; 299*cb5caa98Sdjl } 300*cb5caa98Sdjl else 301*cb5caa98Sdjl goto barf_line; 302*cb5caa98Sdjl 303*cb5caa98Sdjl if (__NSW_SUCCESS_ACTION(act) && 304*cb5caa98Sdjl strcasecmp(tokenp, 305*cb5caa98Sdjl __NSW_STR_SUCCESS) == 0) { 306*cb5caa98Sdjl lkp->actions[__NSW_SUCCESS] = act; 307*cb5caa98Sdjl } else if (__NSW_NOTFOUND_ACTION(act) && 308*cb5caa98Sdjl strcasecmp(tokenp, 309*cb5caa98Sdjl __NSW_STR_NOTFOUND) == 0) { 310*cb5caa98Sdjl lkp->actions[__NSW_NOTFOUND] = act; 311*cb5caa98Sdjl } else if (__NSW_UNAVAIL_ACTION(act) && 312*cb5caa98Sdjl strcasecmp(tokenp, 313*cb5caa98Sdjl __NSW_STR_UNAVAIL) == 0) { 314*cb5caa98Sdjl lkp->actions[__NSW_UNAVAIL] = act; 315*cb5caa98Sdjl } else if (__NSW_TRYAGAIN_ACTION(act) && 316*cb5caa98Sdjl strcasecmp(tokenp, 317*cb5caa98Sdjl __NSW_STR_TRYAGAIN) == 0) { 318*cb5caa98Sdjl lkp->actions[__NSW_TRYAGAIN] = act; 319*cb5caa98Sdjl if (strcasecmp(lkp->service_name, 320*cb5caa98Sdjl "nis") == 0) 321*cb5caa98Sdjl lkp->actions[ 322*cb5caa98Sdjl __NSW_NISSERVDNS_TRYAGAIN] 323*cb5caa98Sdjl = act; 324*cb5caa98Sdjl if (act == __NSW_TRYAGAIN_NTIMES) 325*cb5caa98Sdjl lkp->max_retries = 326*cb5caa98Sdjl dns_continue ? 327*cb5caa98Sdjl dns_tryagain_retry : ntimes; 328*cb5caa98Sdjl } else { 329*cb5caa98Sdjl /*EMPTY*/ 330*cb5caa98Sdjl /* 331*cb5caa98Sdjl * convert string tokenp to integer 332*cb5caa98Sdjl * and put in long_errs 333*cb5caa98Sdjl */ 334*cb5caa98Sdjl } 335*cb5caa98Sdjl if (end_crit) { 336*cb5caa98Sdjl linep = spaceskip(p); 337*cb5caa98Sdjl if (*linep == '\0' || *linep == '\n') 338*cb5caa98Sdjl return (cfp); 339*cb5caa98Sdjl break; /* process next naming service */ 340*cb5caa98Sdjl } 341*cb5caa98Sdjl linep = p; 342*cb5caa98Sdjl } /* end of while loop for a name service's criteria */ 343*cb5caa98Sdjl } else { 344*cb5caa98Sdjl /* 345*cb5caa98Sdjl * no criteria for this naming service. 346*cb5caa98Sdjl * linep points to name service, but not null 347*cb5caa98Sdjl * terminated. 348*cb5caa98Sdjl */ 349*cb5caa98Sdjl p = labelskip(linep); 350*cb5caa98Sdjl if (*p == '\0' || *p == '\n') { 351*cb5caa98Sdjl *p = '\0'; 352*cb5caa98Sdjl lkp->service_name = strdup(linep); 353*cb5caa98Sdjl set_dns_default_lkp(lkp); 354*cb5caa98Sdjl cfp->num_lookups++; 355*cb5caa98Sdjl return (cfp); 356*cb5caa98Sdjl } 357*cb5caa98Sdjl if (*p != ' ' && *p != '\t') 358*cb5caa98Sdjl goto barf_line; 359*cb5caa98Sdjl *p++ = '\0'; 360*cb5caa98Sdjl lkp->service_name = strdup(linep); 361*cb5caa98Sdjl set_dns_default_lkp(lkp); 362*cb5caa98Sdjl cfp->num_lookups++; 363*cb5caa98Sdjl linep = spaceskip(p); 364*cb5caa98Sdjl } 365*cb5caa98Sdjl } /* end of while(1) loop for a name service */ 366*cb5caa98Sdjl 367*cb5caa98Sdjl barf_line: 368*cb5caa98Sdjl freeconf_v1(cfp); 369*cb5caa98Sdjl *errp = __NSW_CONF_PARSE_NOPOLICY; 370*cb5caa98Sdjl return (NULL); 371*cb5caa98Sdjl } 372*cb5caa98Sdjl 373*cb5caa98Sdjl int 374*cb5caa98Sdjl __nsw_freeconfig_v1( 375*cb5caa98Sdjl struct __nsw_switchconfig_v1 *conf) 376*cb5caa98Sdjl { 377*cb5caa98Sdjl freeconf_v1(conf); 378*cb5caa98Sdjl return (0); 379*cb5caa98Sdjl } 380