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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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
43 * printers: user files nis
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
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
;
95 freeconf_v1(struct __nsw_switchconfig_v1
*cfp
)
101 struct __nsw_lookup_v1
*nex
, *cur
;
102 for (cur
= cfp
->lookups
; cur
; cur
= nex
) {
103 free(cur
->service_name
);
112 /* give the next non-alpha character */
122 /* give the next non-space character */
127 while (*p
== ' ' || *p
== '\t')
133 * terminate the *cur pointed string by null only if it is
134 * followed by "key" surrounded by zero or more spaces and
135 * return value is the same as the original *cur pointer and
136 * *cur pointer is advanced to the first non {space, key} char
137 * followed by the key. Otherwise, return NULL and keep
141 skip(char **cur
, char key
)
147 tmp
= labelskip(*cur
);
151 *p
++ = '\0'; /* overwrite the key */
154 while (*p
== ' ' || *p
== '\t') {
155 tmpfound
= (*++p
== key
);
158 /* null terminate the return token */
160 p
++; /* skip the key */
165 return (NULL
); /* *cur unchanged */
170 /* Return 1 if the string contains all digits, else return 0. */
180 struct __nsw_switchconfig_v1
*
181 _nsw_getoneconfig_v1(const char *name
, char *linep
, enum __nsw_parse_err
*errp
)
182 /* linep Nota Bene: not const char * */
183 /* errp Meanings are abused a bit */
185 struct __nsw_switchconfig_v1
*cfp
;
186 struct __nsw_lookup_v1
*lkp
, **lkq
;
191 *errp
= __NSW_CONF_PARSE_SUCCESS
;
193 if ((cfp
= calloc(1, sizeof (struct __nsw_switchconfig_v1
)))
195 *errp
= __NSW_CONF_PARSE_SYSERR
;
198 cfp
->dbase
= strdup(name
);
201 /* linep points to a naming service name */
205 /* white space following the last service */
206 if (*linep
== '\0' || *linep
== '\n') {
209 if ((lkp
= calloc(1, sizeof (struct __nsw_lookup_v1
)))
211 *errp
= __NSW_CONF_PARSE_SYSERR
;
219 for (i
= 0; i
< __NSW_STD_ERRS_V1
; i
++)
220 if (i
== __NSW_SUCCESS
)
221 lkp
->actions
[i
] = __NSW_RETURN
;
222 else if (i
== __NSW_TRYAGAIN
)
223 lkp
->actions
[i
] = __NSW_TRYAGAIN_FOREVER
;
225 lkp
->actions
[i
] = __NSW_CONTINUE
;
227 /* get criteria for the naming service */
228 if (tokenp
= skip(&linep
, '[')) { /* got criteria */
230 /* premature end, illegal char following [ */
231 if (!islabel(*linep
))
233 lkp
->service_name
= strdup(tokenp
);
236 set_dns_default_lkp(lkp
);
240 /* linep points to a switch_err */
242 int ntimes
= 0; /* try again max N times */
243 int dns_continue
= 0;
245 if ((tokenp
= skip(&linep
, '=')) == NULL
) {
249 /* premature end, ill char following = */
250 if (!islabel(*linep
))
253 /* linep points to the string following '=' */
254 p
= labelskip(linep
);
257 else if (*p
!= ' ' && *p
!= '\t')
259 *p
++ = '\0'; /* null terminate linep */
265 } else if (*p
== '\0' || *p
== '\n') {
267 } else if (!islabel(*p
))
268 /* p better be the next switch_err */
271 if (strcasecmp(linep
, __NSW_STR_RETURN
) == 0)
273 else if (strcasecmp(linep
,
274 __NSW_STR_CONTINUE
) == 0) {
275 if (strcasecmp(lkp
->service_name
,
281 * Add one more condition
282 * so it retries only if it's
283 * "dns [TRYAGAIN=continue]"
286 act
= __NSW_TRYAGAIN_NTIMES
;
288 act
= __NSW_CONTINUE
;
289 } else if (strcasecmp(linep
,
290 __NSW_STR_FOREVER
) == 0)
291 act
= __NSW_TRYAGAIN_FOREVER
;
292 else if (alldigits(linep
)) {
293 act
= __NSW_TRYAGAIN_NTIMES
;
294 ntimes
= atoi(linep
);
295 if (ntimes
< 0 || ntimes
> INT_MAX
)
301 if (__NSW_SUCCESS_ACTION(act
) &&
303 __NSW_STR_SUCCESS
) == 0) {
304 lkp
->actions
[__NSW_SUCCESS
] = act
;
305 } else if (__NSW_NOTFOUND_ACTION(act
) &&
307 __NSW_STR_NOTFOUND
) == 0) {
308 lkp
->actions
[__NSW_NOTFOUND
] = act
;
309 } else if (__NSW_UNAVAIL_ACTION(act
) &&
311 __NSW_STR_UNAVAIL
) == 0) {
312 lkp
->actions
[__NSW_UNAVAIL
] = act
;
313 } else if (__NSW_TRYAGAIN_ACTION(act
) &&
315 __NSW_STR_TRYAGAIN
) == 0) {
316 lkp
->actions
[__NSW_TRYAGAIN
] = act
;
317 if (strcasecmp(lkp
->service_name
,
320 __NSW_NISSERVDNS_TRYAGAIN
]
322 if (act
== __NSW_TRYAGAIN_NTIMES
)
325 dns_tryagain_retry
: ntimes
;
329 * convert string tokenp to integer
330 * and put in long_errs
334 linep
= spaceskip(p
);
335 if (*linep
== '\0' || *linep
== '\n')
337 break; /* process next naming service */
340 } /* end of while loop for a name service's criteria */
343 * no criteria for this naming service.
344 * linep points to name service, but not null
347 p
= labelskip(linep
);
348 if (*p
== '\0' || *p
== '\n') {
350 lkp
->service_name
= strdup(linep
);
351 set_dns_default_lkp(lkp
);
355 if (*p
!= ' ' && *p
!= '\t')
358 lkp
->service_name
= strdup(linep
);
359 set_dns_default_lkp(lkp
);
361 linep
= spaceskip(p
);
363 } /* end of while(1) loop for a name service */
367 *errp
= __NSW_CONF_PARSE_NOPOLICY
;
373 struct __nsw_switchconfig_v1
*conf
)