10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1914Scasper * Common Development and Distribution License (the "License"). 6*1914Scasper * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*1914Scasper * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include "synonyms.h" 29*1914Scasper #include "file64.h" 300Sstevel@tonic-gate #include "mtlib.h" 310Sstevel@tonic-gate #include "libc.h" 320Sstevel@tonic-gate #include <synch.h> 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <stdlib.h> 350Sstevel@tonic-gate #include <stdio.h> 36*1914Scasper #include <stdio_ext.h> 370Sstevel@tonic-gate #include <string.h> 380Sstevel@tonic-gate #include <ctype.h> 390Sstevel@tonic-gate #include <limits.h> 400Sstevel@tonic-gate #include <dlfcn.h> 410Sstevel@tonic-gate #include <errno.h> 42*1914Scasper #include "stdiom.h" 430Sstevel@tonic-gate 440Sstevel@tonic-gate #define __NSS_PRIVATE_INTERFACE 450Sstevel@tonic-gate #include "nsswitch_priv.h" 460Sstevel@tonic-gate #undef __NSS_PRIVATE_INTERFACE 470Sstevel@tonic-gate 480Sstevel@tonic-gate #include <syslog.h> 490Sstevel@tonic-gate 500Sstevel@tonic-gate #define islabel(c) (isalnum(c) || (c) == '_') 510Sstevel@tonic-gate 520Sstevel@tonic-gate #define LIBC_STRDUP(new, existing) \ 530Sstevel@tonic-gate if ((new = libc_strdup(existing)) == NULL) { \ 540Sstevel@tonic-gate dup_fail = 1; \ 550Sstevel@tonic-gate goto barf_line; \ 560Sstevel@tonic-gate } 570Sstevel@tonic-gate 580Sstevel@tonic-gate /* 590Sstevel@tonic-gate * This file has all the routines that access the configuration 600Sstevel@tonic-gate * information. 610Sstevel@tonic-gate */ 620Sstevel@tonic-gate 630Sstevel@tonic-gate struct cons_cell_v1 { /* private to the parser */ 640Sstevel@tonic-gate struct __nsw_switchconfig_v1 *sw; 650Sstevel@tonic-gate struct cons_cell_v1 *next; 660Sstevel@tonic-gate }; 670Sstevel@tonic-gate 680Sstevel@tonic-gate struct cons_cell { /* private to the parser */ 690Sstevel@tonic-gate struct __nsw_switchconfig *sw; 700Sstevel@tonic-gate struct cons_cell *next; 710Sstevel@tonic-gate }; 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * Local routines 750Sstevel@tonic-gate */ 760Sstevel@tonic-gate 770Sstevel@tonic-gate static char *skip(char **, char); 780Sstevel@tonic-gate static char *labelskip(char *); 790Sstevel@tonic-gate static char *spaceskip(char *); 800Sstevel@tonic-gate static struct __nsw_switchconfig_v1 *scrounge_cache_v1(const char *); 810Sstevel@tonic-gate static struct __nsw_switchconfig *scrounge_cache(const char *); 820Sstevel@tonic-gate static int add_concell_v1(struct __nsw_switchconfig_v1 *); 830Sstevel@tonic-gate static int add_concell(struct __nsw_switchconfig *); 840Sstevel@tonic-gate static void freeconf_v1(struct __nsw_switchconfig_v1 *); 850Sstevel@tonic-gate static void freeconf(struct __nsw_switchconfig *); 860Sstevel@tonic-gate static int alldigits(char *); 870Sstevel@tonic-gate 880Sstevel@tonic-gate static struct cons_cell_v1 *concell_list_v1; /* stays with add_concell() */ 890Sstevel@tonic-gate static struct cons_cell *concell_list; /* stays with add_concell() */ 900Sstevel@tonic-gate 910Sstevel@tonic-gate /* 920Sstevel@tonic-gate * 930Sstevel@tonic-gate * With the "lookup control" feature, the default criteria for NIS, NIS+, 940Sstevel@tonic-gate * and any new services (e.g. ldap) will be: 950Sstevel@tonic-gate * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=forever] 960Sstevel@tonic-gate * 970Sstevel@tonic-gate * For backward compat, NIS via NIS server in DNS forwarding mode will be: 980Sstevel@tonic-gate * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=continue] 990Sstevel@tonic-gate * 1000Sstevel@tonic-gate * And also for backward compat, the default criteria for DNS will be: 1010Sstevel@tonic-gate * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=continue] 1020Sstevel@tonic-gate */ 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate /* 1070Sstevel@tonic-gate * The BIND resolver normally will retry several times on server non-response. 1080Sstevel@tonic-gate * But now with the "lookup control" feature, we don't want the resolver doing 1090Sstevel@tonic-gate * many retries, rather we want it to return control (reasonably) quickly back 1100Sstevel@tonic-gate * to the switch engine. However, when TRYAGAIN=N or TRYAGAIN=forever is 1110Sstevel@tonic-gate * not explicitly set by the admin in the conf file, we want the old "resolver 1120Sstevel@tonic-gate * retry a few times" rather than no retries at all. 1130Sstevel@tonic-gate */ 1140Sstevel@tonic-gate static int dns_tryagain_retry = 3; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate /* 1170Sstevel@tonic-gate * For backward compat (pre "lookup control"), the dns default behavior is 1180Sstevel@tonic-gate * soft lookup. 1190Sstevel@tonic-gate */ 1200Sstevel@tonic-gate static void 1210Sstevel@tonic-gate set_dns_default_lkp(struct __nsw_lookup_v1 *lkp) 1220Sstevel@tonic-gate { 1230Sstevel@tonic-gate if (strcasecmp(lkp->service_name, "dns") == 0) { 1240Sstevel@tonic-gate lkp->actions[__NSW_TRYAGAIN] = 1250Sstevel@tonic-gate __NSW_TRYAGAIN_NTIMES; 1260Sstevel@tonic-gate lkp->max_retries = dns_tryagain_retry; 1270Sstevel@tonic-gate } 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* 1310Sstevel@tonic-gate * Private interface used by nss_common.c, hence this function is not static 1320Sstevel@tonic-gate */ 1330Sstevel@tonic-gate struct __nsw_switchconfig_v1 * 1340Sstevel@tonic-gate _nsw_getoneconfig_v1(const char *name, char *linep, enum __nsw_parse_err *errp) 1350Sstevel@tonic-gate /* linep Nota Bene: not const char * */ 1360Sstevel@tonic-gate /* errp Meanings are abused a bit */ 1370Sstevel@tonic-gate { 1380Sstevel@tonic-gate struct __nsw_switchconfig_v1 *cfp; 1390Sstevel@tonic-gate struct __nsw_lookup_v1 *lkp, **lkq; 1400Sstevel@tonic-gate int end_crit, dup_fail = 0; 1410Sstevel@tonic-gate action_t act; 1420Sstevel@tonic-gate char *p, *tokenp; 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_SUCCESS; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate if ((cfp = libc_malloc(sizeof (struct __nsw_switchconfig_v1))) 1470Sstevel@tonic-gate == NULL) { 1480Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_SYSERR; 1490Sstevel@tonic-gate return (NULL); 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate LIBC_STRDUP(cfp->dbase, name); 1520Sstevel@tonic-gate lkq = &cfp->lookups; 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate /* linep points to a naming service name */ 1550Sstevel@tonic-gate for (;;) { 1560Sstevel@tonic-gate int i; 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate /* white space following the last service */ 1590Sstevel@tonic-gate if (*linep == '\0' || *linep == '\n') { 1600Sstevel@tonic-gate return (cfp); 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate if ((lkp = libc_malloc(sizeof (struct __nsw_lookup_v1))) 1630Sstevel@tonic-gate == NULL) { 1640Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_SYSERR; 1650Sstevel@tonic-gate freeconf_v1(cfp); 1660Sstevel@tonic-gate return (NULL); 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate *lkq = lkp; 1700Sstevel@tonic-gate lkq = &lkp->next; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate for (i = 0; i < __NSW_STD_ERRS_V1; i++) 1730Sstevel@tonic-gate if (i == __NSW_SUCCESS) 1740Sstevel@tonic-gate lkp->actions[i] = __NSW_RETURN; 1750Sstevel@tonic-gate else if (i == __NSW_TRYAGAIN) 1760Sstevel@tonic-gate lkp->actions[i] = __NSW_TRYAGAIN_FOREVER; 1770Sstevel@tonic-gate else 1780Sstevel@tonic-gate lkp->actions[i] = __NSW_CONTINUE; 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate /* get criteria for the naming service */ 1810Sstevel@tonic-gate if (tokenp = skip(&linep, '[')) { /* got criteria */ 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate /* premature end, illegal char following [ */ 1840Sstevel@tonic-gate if (!islabel(*linep)) 1850Sstevel@tonic-gate goto barf_line; 1860Sstevel@tonic-gate LIBC_STRDUP(lkp->service_name, tokenp); 1870Sstevel@tonic-gate cfp->num_lookups++; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate set_dns_default_lkp(lkp); 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate end_crit = 0; 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate /* linep points to a switch_err */ 1940Sstevel@tonic-gate for (;;) { 1950Sstevel@tonic-gate int ntimes = 0; /* try again max N times */ 1960Sstevel@tonic-gate int dns_continue = 0; 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate if ((tokenp = skip(&linep, '=')) == NULL) { 1990Sstevel@tonic-gate goto barf_line; 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate /* premature end, ill char following = */ 2030Sstevel@tonic-gate if (!islabel(*linep)) 2040Sstevel@tonic-gate goto barf_line; 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate /* linep points to the string following '=' */ 2070Sstevel@tonic-gate p = labelskip(linep); 2080Sstevel@tonic-gate if (*p == ']') 2090Sstevel@tonic-gate end_crit = 1; 2100Sstevel@tonic-gate else if (*p != ' ' && *p != '\t') 2110Sstevel@tonic-gate goto barf_line; 2120Sstevel@tonic-gate *p++ = '\0'; /* null terminate linep */ 2130Sstevel@tonic-gate p = spaceskip(p); 2140Sstevel@tonic-gate if (!end_crit) { 2150Sstevel@tonic-gate if (*p == ']') { 2160Sstevel@tonic-gate end_crit = 1; 2170Sstevel@tonic-gate *p++ = '\0'; 2180Sstevel@tonic-gate } else if (*p == '\0' || *p == '\n') { 2190Sstevel@tonic-gate return (cfp); 2200Sstevel@tonic-gate } else if (!islabel(*p)) 2210Sstevel@tonic-gate /* p better be the next switch_err */ 2220Sstevel@tonic-gate goto barf_line; 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate if (strcasecmp(linep, __NSW_STR_RETURN) == 0) 2250Sstevel@tonic-gate act = __NSW_RETURN; 2260Sstevel@tonic-gate else if (strcasecmp(linep, 2270Sstevel@tonic-gate __NSW_STR_CONTINUE) == 0) { 2280Sstevel@tonic-gate if (strcasecmp(lkp->service_name, 2290Sstevel@tonic-gate "dns") == 0 && 2300Sstevel@tonic-gate strcasecmp(tokenp, 2310Sstevel@tonic-gate __NSW_STR_TRYAGAIN) 2320Sstevel@tonic-gate == 0) { 2330Sstevel@tonic-gate /* 2340Sstevel@tonic-gate * Add one more condition 2350Sstevel@tonic-gate * so it retries only if it's 2360Sstevel@tonic-gate * "dns [TRYAGAIN=continue]" 2370Sstevel@tonic-gate */ 2380Sstevel@tonic-gate dns_continue = 1; 2390Sstevel@tonic-gate act = __NSW_TRYAGAIN_NTIMES; 2400Sstevel@tonic-gate } else 2410Sstevel@tonic-gate act = __NSW_CONTINUE; 2420Sstevel@tonic-gate } else if (strcasecmp(linep, 2430Sstevel@tonic-gate __NSW_STR_FOREVER) == 0) 2440Sstevel@tonic-gate act = __NSW_TRYAGAIN_FOREVER; 2450Sstevel@tonic-gate else if (alldigits(linep)) { 2460Sstevel@tonic-gate act = __NSW_TRYAGAIN_NTIMES; 2470Sstevel@tonic-gate ntimes = atoi(linep); 2480Sstevel@tonic-gate if (ntimes < 0 || ntimes > INT_MAX) 2490Sstevel@tonic-gate ntimes = 0; 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate else 2520Sstevel@tonic-gate goto barf_line; 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate if (__NSW_SUCCESS_ACTION(act) && 2550Sstevel@tonic-gate strcasecmp(tokenp, 2560Sstevel@tonic-gate __NSW_STR_SUCCESS) == 0) { 2570Sstevel@tonic-gate lkp->actions[__NSW_SUCCESS] = act; 2580Sstevel@tonic-gate } else if (__NSW_NOTFOUND_ACTION(act) && 2590Sstevel@tonic-gate strcasecmp(tokenp, 2600Sstevel@tonic-gate __NSW_STR_NOTFOUND) == 0) { 2610Sstevel@tonic-gate lkp->actions[__NSW_NOTFOUND] = act; 2620Sstevel@tonic-gate } else if (__NSW_UNAVAIL_ACTION(act) && 2630Sstevel@tonic-gate strcasecmp(tokenp, 2640Sstevel@tonic-gate __NSW_STR_UNAVAIL) == 0) { 2650Sstevel@tonic-gate lkp->actions[__NSW_UNAVAIL] = act; 2660Sstevel@tonic-gate } else if (__NSW_TRYAGAIN_ACTION(act) && 2670Sstevel@tonic-gate strcasecmp(tokenp, 2680Sstevel@tonic-gate __NSW_STR_TRYAGAIN) == 0) { 2690Sstevel@tonic-gate lkp->actions[__NSW_TRYAGAIN] = act; 2700Sstevel@tonic-gate if (strcasecmp(lkp->service_name, 2710Sstevel@tonic-gate "nis") == 0) 2720Sstevel@tonic-gate lkp->actions[ 2730Sstevel@tonic-gate __NSW_NISSERVDNS_TRYAGAIN] 2740Sstevel@tonic-gate = act; 2750Sstevel@tonic-gate if (act == __NSW_TRYAGAIN_NTIMES) 2760Sstevel@tonic-gate lkp->max_retries = 2770Sstevel@tonic-gate dns_continue ? 2780Sstevel@tonic-gate dns_tryagain_retry : ntimes; 2790Sstevel@tonic-gate } else { 2800Sstevel@tonic-gate /*EMPTY*/ 2810Sstevel@tonic-gate /* 2820Sstevel@tonic-gate * convert string tokenp to integer 2830Sstevel@tonic-gate * and put in long_errs 2840Sstevel@tonic-gate */ 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate if (end_crit) { 2870Sstevel@tonic-gate linep = spaceskip(p); 2880Sstevel@tonic-gate if (*linep == '\0' || *linep == '\n') 2890Sstevel@tonic-gate return (cfp); 2900Sstevel@tonic-gate break; /* process next naming service */ 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate linep = p; 2930Sstevel@tonic-gate } /* end of while loop for a name service's criteria */ 2940Sstevel@tonic-gate } else { 2950Sstevel@tonic-gate /* 2960Sstevel@tonic-gate * no criteria for this naming service. 2970Sstevel@tonic-gate * linep points to name service, but not null 2980Sstevel@tonic-gate * terminated. 2990Sstevel@tonic-gate */ 3000Sstevel@tonic-gate p = labelskip(linep); 3010Sstevel@tonic-gate if (*p == '\0' || *p == '\n') { 3020Sstevel@tonic-gate *p = '\0'; 3030Sstevel@tonic-gate LIBC_STRDUP(lkp->service_name, linep); 3040Sstevel@tonic-gate set_dns_default_lkp(lkp); 3050Sstevel@tonic-gate cfp->num_lookups++; 3060Sstevel@tonic-gate return (cfp); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate if (*p != ' ' && *p != '\t') 3090Sstevel@tonic-gate goto barf_line; 3100Sstevel@tonic-gate *p++ = '\0'; 3110Sstevel@tonic-gate LIBC_STRDUP(lkp->service_name, linep); 3120Sstevel@tonic-gate set_dns_default_lkp(lkp); 3130Sstevel@tonic-gate cfp->num_lookups++; 3140Sstevel@tonic-gate linep = spaceskip(p); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate } /* end of while(1) loop for a name service */ 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate barf_line: 3190Sstevel@tonic-gate freeconf_v1(cfp); 3200Sstevel@tonic-gate *errp = dup_fail ? __NSW_CONF_PARSE_SYSERR : __NSW_CONF_PARSE_NOPOLICY; 3210Sstevel@tonic-gate return (NULL); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate /* 3250Sstevel@tonic-gate * Private interface used by nss_common.c, hence this function is not static 3260Sstevel@tonic-gate */ 3270Sstevel@tonic-gate struct __nsw_switchconfig * 3280Sstevel@tonic-gate _nsw_getoneconfig(const char *name, char *linep, enum __nsw_parse_err *errp) 3290Sstevel@tonic-gate /* linep Nota Bene: not const char * */ 3300Sstevel@tonic-gate /* errp Meanings are abused a bit */ 3310Sstevel@tonic-gate { 3320Sstevel@tonic-gate struct __nsw_switchconfig *cfp; 3330Sstevel@tonic-gate struct __nsw_lookup *lkp, **lkq; 3340Sstevel@tonic-gate int end_crit, dup_fail = 0; 3350Sstevel@tonic-gate action_t act; 3360Sstevel@tonic-gate char *p, *tokenp; 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_SUCCESS; 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate if ((cfp = libc_malloc(sizeof (struct __nsw_switchconfig))) 3410Sstevel@tonic-gate == NULL) { 3420Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_SYSERR; 3430Sstevel@tonic-gate return (NULL); 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate LIBC_STRDUP(cfp->dbase, name); 3460Sstevel@tonic-gate lkq = &cfp->lookups; 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate /* linep points to a naming service name */ 3490Sstevel@tonic-gate for (;;) { 3500Sstevel@tonic-gate int i; 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate /* white space following the last service */ 3530Sstevel@tonic-gate if (*linep == '\0' || *linep == '\n') { 3540Sstevel@tonic-gate return (cfp); 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate if ((lkp = libc_malloc(sizeof (struct __nsw_lookup))) 3570Sstevel@tonic-gate == NULL) { 3580Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_SYSERR; 3590Sstevel@tonic-gate freeconf(cfp); 3600Sstevel@tonic-gate return (NULL); 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate *lkq = lkp; 3640Sstevel@tonic-gate lkq = &lkp->next; 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate for (i = 0; i < __NSW_STD_ERRS; i++) 3670Sstevel@tonic-gate if (i == __NSW_SUCCESS) 3680Sstevel@tonic-gate lkp->actions[i] = 1; 3690Sstevel@tonic-gate else 3700Sstevel@tonic-gate lkp->actions[i] = 0; 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate /* get criteria for the naming service */ 3730Sstevel@tonic-gate if (tokenp = skip(&linep, '[')) { /* got criteria */ 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate /* premature end, illegal char following [ */ 3760Sstevel@tonic-gate if (!islabel(*linep)) 3770Sstevel@tonic-gate goto barf_line; 3780Sstevel@tonic-gate LIBC_STRDUP(lkp->service_name, tokenp); 3790Sstevel@tonic-gate cfp->num_lookups++; 3800Sstevel@tonic-gate end_crit = 0; 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate /* linep points to a switch_err */ 3830Sstevel@tonic-gate for (;;) { 3840Sstevel@tonic-gate if ((tokenp = skip(&linep, '=')) == NULL) { 3850Sstevel@tonic-gate goto barf_line; 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate /* premature end, ill char following = */ 3890Sstevel@tonic-gate if (!islabel(*linep)) 3900Sstevel@tonic-gate goto barf_line; 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate /* linep points to the string following '=' */ 3930Sstevel@tonic-gate p = labelskip(linep); 3940Sstevel@tonic-gate if (*p == ']') 3950Sstevel@tonic-gate end_crit = 1; 3960Sstevel@tonic-gate else if (*p != ' ' && *p != '\t') 3970Sstevel@tonic-gate goto barf_line; 3980Sstevel@tonic-gate *p++ = '\0'; /* null terminate linep */ 3990Sstevel@tonic-gate p = spaceskip(p); 4000Sstevel@tonic-gate if (!end_crit) { 4010Sstevel@tonic-gate if (*p == ']') { 4020Sstevel@tonic-gate end_crit = 1; 4030Sstevel@tonic-gate *p++ = '\0'; 4040Sstevel@tonic-gate } else if (*p == '\0' || *p == '\n') 4050Sstevel@tonic-gate return (cfp); 4060Sstevel@tonic-gate else if (!islabel(*p)) 4070Sstevel@tonic-gate /* p better be the next switch_err */ 4080Sstevel@tonic-gate goto barf_line; 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate if (strcasecmp(linep, __NSW_STR_RETURN) == 0) 4110Sstevel@tonic-gate act = __NSW_RETURN; 4120Sstevel@tonic-gate else if (strcasecmp(linep, 4130Sstevel@tonic-gate __NSW_STR_CONTINUE) == 0) 4140Sstevel@tonic-gate act = __NSW_CONTINUE; 4150Sstevel@tonic-gate else if (strcasecmp(linep, 4160Sstevel@tonic-gate __NSW_STR_FOREVER) == 0) 4170Sstevel@tonic-gate /* 4180Sstevel@tonic-gate * =forever or =N might be in conf file 4190Sstevel@tonic-gate * but old progs won't expect it. 4200Sstevel@tonic-gate */ 4210Sstevel@tonic-gate act = __NSW_RETURN; 4220Sstevel@tonic-gate else if (alldigits(linep)) 4230Sstevel@tonic-gate act = __NSW_CONTINUE; 4240Sstevel@tonic-gate else 4250Sstevel@tonic-gate goto barf_line; 4260Sstevel@tonic-gate if (strcasecmp(tokenp, 4270Sstevel@tonic-gate __NSW_STR_SUCCESS) == 0) { 4280Sstevel@tonic-gate lkp->actions[__NSW_SUCCESS] = act; 4290Sstevel@tonic-gate } else if (strcasecmp(tokenp, 4300Sstevel@tonic-gate __NSW_STR_NOTFOUND) == 0) { 4310Sstevel@tonic-gate lkp->actions[__NSW_NOTFOUND] = act; 4320Sstevel@tonic-gate } else if (strcasecmp(tokenp, 4330Sstevel@tonic-gate __NSW_STR_UNAVAIL) == 0) { 4340Sstevel@tonic-gate lkp->actions[__NSW_UNAVAIL] = act; 4350Sstevel@tonic-gate } else if (strcasecmp(tokenp, 4360Sstevel@tonic-gate __NSW_STR_TRYAGAIN) == 0) { 4370Sstevel@tonic-gate lkp->actions[__NSW_TRYAGAIN] = act; 4380Sstevel@tonic-gate } else { 4390Sstevel@tonic-gate /*EMPTY*/ 4400Sstevel@tonic-gate /* 4410Sstevel@tonic-gate * convert string tokenp to integer 4420Sstevel@tonic-gate * and put in long_errs 4430Sstevel@tonic-gate */ 4440Sstevel@tonic-gate } 4450Sstevel@tonic-gate if (end_crit) { 4460Sstevel@tonic-gate linep = spaceskip(p); 4470Sstevel@tonic-gate if (*linep == '\0' || *linep == '\n') 4480Sstevel@tonic-gate return (cfp); 4490Sstevel@tonic-gate break; /* process next naming service */ 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate linep = p; 4520Sstevel@tonic-gate } /* end of while loop for a name service's criteria */ 4530Sstevel@tonic-gate } else { 4540Sstevel@tonic-gate /* 4550Sstevel@tonic-gate * no criteria for this naming service. 4560Sstevel@tonic-gate * linep points to name service, but not null 4570Sstevel@tonic-gate * terminated. 4580Sstevel@tonic-gate */ 4590Sstevel@tonic-gate p = labelskip(linep); 4600Sstevel@tonic-gate if (*p == '\0' || *p == '\n') { 4610Sstevel@tonic-gate *p = '\0'; 4620Sstevel@tonic-gate LIBC_STRDUP(lkp->service_name, linep); 4630Sstevel@tonic-gate cfp->num_lookups++; 4640Sstevel@tonic-gate return (cfp); 4650Sstevel@tonic-gate } 4660Sstevel@tonic-gate if (*p != ' ' && *p != '\t') 4670Sstevel@tonic-gate goto barf_line; 4680Sstevel@tonic-gate *p++ = '\0'; 4690Sstevel@tonic-gate LIBC_STRDUP(lkp->service_name, linep); 4700Sstevel@tonic-gate cfp->num_lookups++; 4710Sstevel@tonic-gate linep = spaceskip(p); 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate } /* end of while(1) loop for a name service */ 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate barf_line: 4760Sstevel@tonic-gate freeconf(cfp); 4770Sstevel@tonic-gate *errp = dup_fail ? __NSW_CONF_PARSE_SYSERR : __NSW_CONF_PARSE_NOPOLICY; 4780Sstevel@tonic-gate return (NULL); 4790Sstevel@tonic-gate } 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate static mutex_t serialize_config_v1 = DEFAULTMUTEX; 4820Sstevel@tonic-gate static mutex_t serialize_config = DEFAULTMUTEX; 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate static void 4850Sstevel@tonic-gate syslog_warning(const char *dbase) 4860Sstevel@tonic-gate { 4870Sstevel@tonic-gate syslog(LOG_WARNING, 4880Sstevel@tonic-gate "libc: bad lookup policy for %s in %s, using defaults..\n", 4890Sstevel@tonic-gate dbase, __NSW_CONFIG_FILE); 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate 492*1914Scasper /* 493*1914Scasper * Since we cannot call malloc() or lock any of the ordinary mutexes 494*1914Scasper * while we hold an lmutex_lock(), we open the file outside the lock 495*1914Scasper * and disable locking on the file; the latter is fine because we're 496*1914Scasper * reading the fp only from a single thread. 497*1914Scasper */ 498*1914Scasper static FILE * 499*1914Scasper open_conf(void) 500*1914Scasper { 501*1914Scasper FILE *fp = fopen(__NSW_CONFIG_FILE, "rF"); 502*1914Scasper 503*1914Scasper if (fp != NULL) { 504*1914Scasper if (_findbuf(fp) == NULL) { 505*1914Scasper (void) fclose(fp); 506*1914Scasper return (NULL); 507*1914Scasper } 508*1914Scasper SET_IONOLOCK(fp); 509*1914Scasper } 510*1914Scasper return (fp); 511*1914Scasper } 512*1914Scasper 5130Sstevel@tonic-gate struct __nsw_switchconfig_v1 * 5140Sstevel@tonic-gate __nsw_getconfig_v1(const char *dbase, enum __nsw_parse_err *errp) 5150Sstevel@tonic-gate { 5160Sstevel@tonic-gate struct __nsw_switchconfig_v1 *cfp, *retp = NULL; 5170Sstevel@tonic-gate int syslog_error = 0; 518*1914Scasper FILE *fp = NULL; 5190Sstevel@tonic-gate char *linep; 5200Sstevel@tonic-gate char lineq[BUFSIZ]; 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate lmutex_lock(&serialize_config_v1); 523*1914Scasper top: 5240Sstevel@tonic-gate if (cfp = scrounge_cache_v1(dbase)) { 5250Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_SUCCESS; 5260Sstevel@tonic-gate lmutex_unlock(&serialize_config_v1); 527*1914Scasper if (fp != NULL) 528*1914Scasper (void) fclose(fp); 5290Sstevel@tonic-gate return (cfp); 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate 532*1914Scasper if (fp == NULL) { 533*1914Scasper struct cons_cell_v1 *cp = concell_list_v1; 534*1914Scasper 5350Sstevel@tonic-gate lmutex_unlock(&serialize_config_v1); 536*1914Scasper /* open_conf() must be called w/o locks held */ 537*1914Scasper if ((fp = open_conf()) == NULL) { 538*1914Scasper *errp = __NSW_CONF_PARSE_NOFILE; 539*1914Scasper return (NULL); 540*1914Scasper } 541*1914Scasper lmutex_lock(&serialize_config_v1); 542*1914Scasper /* Cache changed? */ 543*1914Scasper if (cp != concell_list_v1) 544*1914Scasper goto top; 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_NOPOLICY; 548*1914Scasper while (linep = fgets(lineq, BUFSIZ, fp)) { 5490Sstevel@tonic-gate enum __nsw_parse_err line_err; 5500Sstevel@tonic-gate char *tokenp, *comment; 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate /* 5530Sstevel@tonic-gate * Ignore portion of line following the comment character '#'. 5540Sstevel@tonic-gate */ 5550Sstevel@tonic-gate if ((comment = strchr(linep, '#')) != NULL) { 5560Sstevel@tonic-gate *comment = '\0'; 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate /* 5590Sstevel@tonic-gate * skip past blank lines. 5600Sstevel@tonic-gate * otherwise, cache as a struct switchconfig. 5610Sstevel@tonic-gate */ 5620Sstevel@tonic-gate if ((*linep == '\0') || isspace(*linep)) { 5630Sstevel@tonic-gate continue; 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate if ((tokenp = skip(&linep, ':')) == NULL) { 5660Sstevel@tonic-gate continue; /* ignore this line */ 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate if (cfp = scrounge_cache_v1(tokenp)) { 5690Sstevel@tonic-gate continue; /* ? somehow this database is in the cache */ 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate if (cfp = _nsw_getoneconfig_v1(tokenp, linep, &line_err)) { 5720Sstevel@tonic-gate (void) add_concell_v1(cfp); 5730Sstevel@tonic-gate if (strcmp(cfp->dbase, dbase) == 0) { 5740Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_SUCCESS; 5750Sstevel@tonic-gate retp = cfp; 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate } else { 5780Sstevel@tonic-gate /* 5790Sstevel@tonic-gate * Got an error on this line, if it is a system 5800Sstevel@tonic-gate * error we might as well give right now. If it 5810Sstevel@tonic-gate * is a parse error on the second entry of the 5820Sstevel@tonic-gate * database we are looking for and the first one 5830Sstevel@tonic-gate * was a good entry we end up logging the following 5840Sstevel@tonic-gate * syslog message and using a default policy instead. 5850Sstevel@tonic-gate */ 5860Sstevel@tonic-gate if (line_err == __NSW_CONF_PARSE_SYSERR) { 5870Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_SYSERR; 5880Sstevel@tonic-gate break; 5890Sstevel@tonic-gate } else if (line_err == __NSW_CONF_PARSE_NOPOLICY && 5900Sstevel@tonic-gate strcmp(tokenp, dbase) == 0) { 5910Sstevel@tonic-gate syslog_error = 1; 5920Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_NOPOLICY; 5930Sstevel@tonic-gate break; 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate /* 5960Sstevel@tonic-gate * Else blithely ignore problems on this line and 5970Sstevel@tonic-gate * go ahead with the next line. 5980Sstevel@tonic-gate */ 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate lmutex_unlock(&serialize_config_v1); 6020Sstevel@tonic-gate /* 603*1914Scasper * We have to drop the lock before calling fclose()/syslog(). 6040Sstevel@tonic-gate */ 605*1914Scasper (void) fclose(fp); 6060Sstevel@tonic-gate if (syslog_error) 6070Sstevel@tonic-gate syslog_warning(dbase); 6080Sstevel@tonic-gate return (retp); 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate struct __nsw_switchconfig * 6120Sstevel@tonic-gate __nsw_getconfig(const char *dbase, enum __nsw_parse_err *errp) 6130Sstevel@tonic-gate { 6140Sstevel@tonic-gate struct __nsw_switchconfig *cfp, *retp = NULL; 6150Sstevel@tonic-gate int syslog_error = 0; 616*1914Scasper FILE *fp = NULL; 6170Sstevel@tonic-gate char *linep; 6180Sstevel@tonic-gate char lineq[BUFSIZ]; 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate lmutex_lock(&serialize_config); 621*1914Scasper top: 6220Sstevel@tonic-gate if (cfp = scrounge_cache(dbase)) { 6230Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_SUCCESS; 6240Sstevel@tonic-gate lmutex_unlock(&serialize_config); 625*1914Scasper if (fp != NULL) 626*1914Scasper (void) fclose(fp); 6270Sstevel@tonic-gate return (cfp); 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate 630*1914Scasper if (fp == NULL) { 631*1914Scasper struct cons_cell *cp = concell_list; 632*1914Scasper /* open_conf() must be called w/o locks held */ 6330Sstevel@tonic-gate lmutex_unlock(&serialize_config); 634*1914Scasper if ((fp = open_conf()) == NULL) { 635*1914Scasper *errp = __NSW_CONF_PARSE_NOFILE; 636*1914Scasper return (NULL); 637*1914Scasper } 638*1914Scasper lmutex_lock(&serialize_config); 639*1914Scasper /* Cache changed? */ 640*1914Scasper if (cp != concell_list) 641*1914Scasper goto top; 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_NOPOLICY; 645*1914Scasper while (linep = fgets(lineq, BUFSIZ, fp)) { 6460Sstevel@tonic-gate enum __nsw_parse_err line_err; 6470Sstevel@tonic-gate char *tokenp, *comment; 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate /* 6500Sstevel@tonic-gate * Ignore portion of line following the comment character '#'. 6510Sstevel@tonic-gate */ 6520Sstevel@tonic-gate if ((comment = strchr(linep, '#')) != NULL) { 6530Sstevel@tonic-gate *comment = '\0'; 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate /* 6560Sstevel@tonic-gate * skip past blank lines. 6570Sstevel@tonic-gate * otherwise, cache as a struct switchconfig. 6580Sstevel@tonic-gate */ 6590Sstevel@tonic-gate if ((*linep == '\0') || isspace(*linep)) { 6600Sstevel@tonic-gate continue; 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate if ((tokenp = skip(&linep, ':')) == NULL) { 6630Sstevel@tonic-gate continue; /* ignore this line */ 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate if (cfp = scrounge_cache(tokenp)) { 6660Sstevel@tonic-gate continue; /* ? somehow this database is in the cache */ 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate if (cfp = _nsw_getoneconfig(tokenp, linep, &line_err)) { 6690Sstevel@tonic-gate (void) add_concell(cfp); 6700Sstevel@tonic-gate if (strcmp(cfp->dbase, dbase) == 0) { 6710Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_SUCCESS; 6720Sstevel@tonic-gate retp = cfp; 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate } else { 6750Sstevel@tonic-gate /* 6760Sstevel@tonic-gate * Got an error on this line, if it is a system 6770Sstevel@tonic-gate * error we might as well give right now. If it 6780Sstevel@tonic-gate * is a parse error on the second entry of the 6790Sstevel@tonic-gate * database we are looking for and the first one 6800Sstevel@tonic-gate * was a good entry we end up logging the following 6810Sstevel@tonic-gate * syslog message and using a default policy instead. 6820Sstevel@tonic-gate */ 6830Sstevel@tonic-gate if (line_err == __NSW_CONF_PARSE_SYSERR) { 6840Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_SYSERR; 6850Sstevel@tonic-gate break; 6860Sstevel@tonic-gate } else if (line_err == __NSW_CONF_PARSE_NOPOLICY && 6870Sstevel@tonic-gate strcmp(tokenp, dbase) == 0) { 6880Sstevel@tonic-gate syslog_error = 1; 6890Sstevel@tonic-gate *errp = __NSW_CONF_PARSE_NOPOLICY; 6900Sstevel@tonic-gate break; 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate /* 6930Sstevel@tonic-gate * Else blithely ignore problems on this line and 6940Sstevel@tonic-gate * go ahead with the next line. 6950Sstevel@tonic-gate */ 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate lmutex_unlock(&serialize_config); 6990Sstevel@tonic-gate /* 700*1914Scasper * We have to drop the lock before calling fclose()/syslog(). 7010Sstevel@tonic-gate */ 702*1914Scasper (void) fclose(fp); 7030Sstevel@tonic-gate if (syslog_error) 7040Sstevel@tonic-gate syslog_warning(dbase); 7050Sstevel@tonic-gate return (retp); 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate static struct __nsw_switchconfig_v1 * 7100Sstevel@tonic-gate scrounge_cache_v1(const char *dbase) 7110Sstevel@tonic-gate { 7120Sstevel@tonic-gate struct cons_cell_v1 *cellp = concell_list_v1; 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate for (; cellp; cellp = cellp->next) 7150Sstevel@tonic-gate if (strcmp(dbase, cellp->sw->dbase) == 0) 7160Sstevel@tonic-gate return (cellp->sw); 7170Sstevel@tonic-gate return (NULL); 7180Sstevel@tonic-gate } 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate static struct __nsw_switchconfig * 7210Sstevel@tonic-gate scrounge_cache(const char *dbase) 7220Sstevel@tonic-gate { 7230Sstevel@tonic-gate struct cons_cell *cellp = concell_list; 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate for (; cellp; cellp = cellp->next) 7260Sstevel@tonic-gate if (strcmp(dbase, cellp->sw->dbase) == 0) 7270Sstevel@tonic-gate return (cellp->sw); 7280Sstevel@tonic-gate return (NULL); 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate static void 7320Sstevel@tonic-gate freeconf_v1(struct __nsw_switchconfig_v1 *cfp) 7330Sstevel@tonic-gate { 7340Sstevel@tonic-gate if (cfp) { 7350Sstevel@tonic-gate if (cfp->dbase) 7360Sstevel@tonic-gate libc_free(cfp->dbase); 7370Sstevel@tonic-gate if (cfp->lookups) { 7380Sstevel@tonic-gate struct __nsw_lookup_v1 *nex, *cur; 7390Sstevel@tonic-gate for (cur = cfp->lookups; cur; cur = nex) { 7400Sstevel@tonic-gate libc_free(cur->service_name); 7410Sstevel@tonic-gate nex = cur->next; 7420Sstevel@tonic-gate libc_free(cur); 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate libc_free(cfp); 7460Sstevel@tonic-gate } 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate static void 7500Sstevel@tonic-gate freeconf(struct __nsw_switchconfig *cfp) 7510Sstevel@tonic-gate { 7520Sstevel@tonic-gate if (cfp) { 7530Sstevel@tonic-gate if (cfp->dbase) 7540Sstevel@tonic-gate libc_free(cfp->dbase); 7550Sstevel@tonic-gate if (cfp->lookups) { 7560Sstevel@tonic-gate struct __nsw_lookup *nex, *cur; 7570Sstevel@tonic-gate for (cur = cfp->lookups; cur; cur = nex) { 7580Sstevel@tonic-gate libc_free(cur->service_name); 7590Sstevel@tonic-gate nex = cur->next; 7600Sstevel@tonic-gate libc_free(cur); 7610Sstevel@tonic-gate } 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate libc_free(cfp); 7640Sstevel@tonic-gate } 7650Sstevel@tonic-gate } 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate action_t 7680Sstevel@tonic-gate __nsw_extended_action_v1(struct __nsw_lookup_v1 *lkp, int err) 7690Sstevel@tonic-gate { 7700Sstevel@tonic-gate struct __nsw_long_err *lerrp; 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate for (lerrp = lkp->long_errs; lerrp; lerrp = lerrp->next) { 7730Sstevel@tonic-gate if (lerrp->nsw_errno == err) 7740Sstevel@tonic-gate return (lerrp->action); 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate return (__NSW_CONTINUE); 7770Sstevel@tonic-gate } 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate action_t 7800Sstevel@tonic-gate __nsw_extended_action(struct __nsw_lookup *lkp, int err) 7810Sstevel@tonic-gate { 7820Sstevel@tonic-gate struct __nsw_long_err *lerrp; 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate for (lerrp = lkp->long_errs; lerrp; lerrp = lerrp->next) { 7850Sstevel@tonic-gate if (lerrp->nsw_errno == err) 7860Sstevel@tonic-gate return (lerrp->action); 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate return (__NSW_CONTINUE); 7890Sstevel@tonic-gate } 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate /* give the next non-alpha character */ 7930Sstevel@tonic-gate static char * 7940Sstevel@tonic-gate labelskip(char *cur) 7950Sstevel@tonic-gate { 7960Sstevel@tonic-gate char *p = cur; 7970Sstevel@tonic-gate while (islabel(*p)) 7980Sstevel@tonic-gate ++p; 7990Sstevel@tonic-gate return (p); 8000Sstevel@tonic-gate } 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate /* give the next non-space character */ 8030Sstevel@tonic-gate static char * 8040Sstevel@tonic-gate spaceskip(char *cur) 8050Sstevel@tonic-gate { 8060Sstevel@tonic-gate char *p = cur; 8070Sstevel@tonic-gate while (*p == ' ' || *p == '\t') 8080Sstevel@tonic-gate ++p; 8090Sstevel@tonic-gate return (p); 8100Sstevel@tonic-gate } 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate /* 8130Sstevel@tonic-gate * terminate the *cur pointed string by null only if it is 8140Sstevel@tonic-gate * followed by "key" surrounded by zero or more spaces and 8150Sstevel@tonic-gate * return value is the same as the original *cur pointer and 8160Sstevel@tonic-gate * *cur pointer is advanced to the first non {space, key} char 8170Sstevel@tonic-gate * followed by the key. Otherwise, return NULL and keep 8180Sstevel@tonic-gate * *cur unchanged. 8190Sstevel@tonic-gate */ 8200Sstevel@tonic-gate static char * 8210Sstevel@tonic-gate skip(char **cur, char key) 8220Sstevel@tonic-gate { 8230Sstevel@tonic-gate char *p, *tmp; 8240Sstevel@tonic-gate char *q = *cur; 8250Sstevel@tonic-gate int found, tmpfound; 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate tmp = labelskip(*cur); 8280Sstevel@tonic-gate p = tmp; 8290Sstevel@tonic-gate found = (*p == key); 8300Sstevel@tonic-gate if (found) { 8310Sstevel@tonic-gate *p++ = '\0'; /* overwrite the key */ 8320Sstevel@tonic-gate p = spaceskip(p); 8330Sstevel@tonic-gate } else { 8340Sstevel@tonic-gate while (*p == ' ' || *p == '\t') { 8350Sstevel@tonic-gate tmpfound = (*++p == key); 8360Sstevel@tonic-gate if (tmpfound) { 8370Sstevel@tonic-gate found = tmpfound; 8380Sstevel@tonic-gate /* null terminate the return token */ 8390Sstevel@tonic-gate *tmp = '\0'; 8400Sstevel@tonic-gate p++; /* skip the key */ 8410Sstevel@tonic-gate } 8420Sstevel@tonic-gate } 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate if (!found) 8450Sstevel@tonic-gate return (NULL); /* *cur unchanged */ 8460Sstevel@tonic-gate *cur = p; 8470Sstevel@tonic-gate return (q); 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate /* add to the front: LRU */ 8510Sstevel@tonic-gate static int 8520Sstevel@tonic-gate add_concell_v1(struct __nsw_switchconfig_v1 *cfp) 8530Sstevel@tonic-gate { 8540Sstevel@tonic-gate struct cons_cell_v1 *cp; 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate if (cfp == NULL) 8570Sstevel@tonic-gate return (1); 8580Sstevel@tonic-gate if ((cp = libc_malloc(sizeof (struct cons_cell_v1))) == NULL) 8590Sstevel@tonic-gate return (1); 8600Sstevel@tonic-gate cp->sw = cfp; 8610Sstevel@tonic-gate cp->next = concell_list_v1; 8620Sstevel@tonic-gate concell_list_v1 = cp; 8630Sstevel@tonic-gate return (0); 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate /* add to the front: LRU */ 8670Sstevel@tonic-gate static int 8680Sstevel@tonic-gate add_concell(struct __nsw_switchconfig *cfp) 8690Sstevel@tonic-gate { 8700Sstevel@tonic-gate struct cons_cell *cp; 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate if (cfp == NULL) 8730Sstevel@tonic-gate return (1); 8740Sstevel@tonic-gate if ((cp = libc_malloc(sizeof (struct cons_cell))) == NULL) 8750Sstevel@tonic-gate return (1); 8760Sstevel@tonic-gate cp->sw = cfp; 8770Sstevel@tonic-gate cp->next = concell_list; 8780Sstevel@tonic-gate concell_list = cp; 8790Sstevel@tonic-gate return (0); 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate int 8830Sstevel@tonic-gate __nsw_freeconfig_v1(struct __nsw_switchconfig_v1 *conf) 8840Sstevel@tonic-gate { 8850Sstevel@tonic-gate struct cons_cell_v1 *cellp; 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate if (conf == NULL) { 8880Sstevel@tonic-gate return (-1); 8890Sstevel@tonic-gate } 8900Sstevel@tonic-gate /* 8910Sstevel@tonic-gate * Hacked to make life easy for the code in nss_common.c. Free conf 8920Sstevel@tonic-gate * iff it was created by calling _nsw_getoneconfig() directly 8930Sstevel@tonic-gate * rather than by calling nsw_getconfig. 8940Sstevel@tonic-gate */ 8950Sstevel@tonic-gate lmutex_lock(&serialize_config_v1); 8960Sstevel@tonic-gate for (cellp = concell_list_v1; cellp; cellp = cellp->next) { 8970Sstevel@tonic-gate if (cellp->sw == conf) { 8980Sstevel@tonic-gate break; 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate } 9010Sstevel@tonic-gate lmutex_unlock(&serialize_config_v1); 9020Sstevel@tonic-gate if (cellp == NULL) { 9030Sstevel@tonic-gate /* Not in the cache; free it */ 9040Sstevel@tonic-gate freeconf_v1(conf); 9050Sstevel@tonic-gate return (1); 9060Sstevel@tonic-gate } else { 9070Sstevel@tonic-gate /* In the cache; don't free it */ 9080Sstevel@tonic-gate return (0); 9090Sstevel@tonic-gate } 9100Sstevel@tonic-gate } 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate int 9130Sstevel@tonic-gate __nsw_freeconfig(struct __nsw_switchconfig *conf) 9140Sstevel@tonic-gate { 9150Sstevel@tonic-gate struct cons_cell *cellp; 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate if (conf == NULL) { 9180Sstevel@tonic-gate return (-1); 9190Sstevel@tonic-gate } 9200Sstevel@tonic-gate /* 9210Sstevel@tonic-gate * Hacked to make life easy for the code in nss_common.c. Free conf 9220Sstevel@tonic-gate * iff it was created by calling _nsw_getoneconfig() directly 9230Sstevel@tonic-gate * rather than by calling nsw_getconfig. 9240Sstevel@tonic-gate */ 9250Sstevel@tonic-gate lmutex_lock(&serialize_config); 9260Sstevel@tonic-gate for (cellp = concell_list; cellp; cellp = cellp->next) { 9270Sstevel@tonic-gate if (cellp->sw == conf) { 9280Sstevel@tonic-gate break; 9290Sstevel@tonic-gate } 9300Sstevel@tonic-gate } 9310Sstevel@tonic-gate lmutex_unlock(&serialize_config); 9320Sstevel@tonic-gate if (cellp == NULL) { 9330Sstevel@tonic-gate /* Not in the cache; free it */ 9340Sstevel@tonic-gate freeconf(conf); 9350Sstevel@tonic-gate return (1); 9360Sstevel@tonic-gate } else { 9370Sstevel@tonic-gate /* In the cache; don't free it */ 9380Sstevel@tonic-gate return (0); 9390Sstevel@tonic-gate } 9400Sstevel@tonic-gate } 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate /* Return 1 if the string contains all digits, else return 0. */ 9430Sstevel@tonic-gate static int 9440Sstevel@tonic-gate alldigits(char *s) 9450Sstevel@tonic-gate { 9460Sstevel@tonic-gate for (; *s; s++) 9470Sstevel@tonic-gate if (!isdigit(*s)) 9480Sstevel@tonic-gate return (0); 9490Sstevel@tonic-gate return (1); 9500Sstevel@tonic-gate } 951