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