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