xref: /titanic_54/usr/src/cmd/nscd/nscd_nswparse.c (revision cb5caa98562cf06753163f558cbcfe30b8f4673a)
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