1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include "lint.h"
30 #include "file64.h"
31 #include "mtlib.h"
32 #include "libc.h"
33 #include <synch.h>
34 #include <sys/types.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <stdio_ext.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <limits.h>
41 #include <dlfcn.h>
42 #include <errno.h>
43 #include "stdiom.h"
44
45 #define __NSS_PRIVATE_INTERFACE
46 #include "nsswitch_priv.h"
47 #undef __NSS_PRIVATE_INTERFACE
48
49 #include <syslog.h>
50
51 #define islabel(c) (isalnum(c) || (c) == '_')
52
53 #define LIBC_STRDUP(new, existing) \
54 if ((new = libc_strdup(existing)) == NULL) { \
55 dup_fail = 1; \
56 goto barf_line; \
57 }
58
59 /*
60 * This file has all the routines that access the configuration
61 * information.
62 */
63
64 struct cons_cell_v1 { /* private to the parser */
65 struct __nsw_switchconfig_v1 *sw;
66 struct cons_cell_v1 *next;
67 };
68
69 struct cons_cell { /* private to the parser */
70 struct __nsw_switchconfig *sw;
71 struct cons_cell *next;
72 };
73
74 /*
75 * Local routines
76 */
77
78 static char *skip(char **, char);
79 static char *labelskip(char *);
80 static char *spaceskip(char *);
81 static struct __nsw_switchconfig_v1 *scrounge_cache_v1(const char *);
82 static struct __nsw_switchconfig *scrounge_cache(const char *);
83 static int add_concell_v1(struct __nsw_switchconfig_v1 *);
84 static int add_concell(struct __nsw_switchconfig *);
85 static void freeconf_v1(struct __nsw_switchconfig_v1 *);
86 static void freeconf(struct __nsw_switchconfig *);
87 static int alldigits(char *);
88
89 static struct cons_cell_v1 *concell_list_v1; /* stays with add_concell() */
90 static struct cons_cell *concell_list; /* stays with add_concell() */
91
92 /*
93 *
94 * With the "lookup control" feature, the default criteria for NIS, NIS+,
95 * and any new services (e.g. ldap) will be:
96 * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=forever]
97 *
98 * For backward compat, NIS via NIS server in DNS forwarding mode will be:
99 * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=continue]
100 *
101 * And also for backward compat, the default criteria for DNS will be:
102 * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=continue]
103 */
104
105
106
107 /*
108 * The BIND resolver normally will retry several times on server non-response.
109 * But now with the "lookup control" feature, we don't want the resolver doing
110 * many retries, rather we want it to return control (reasonably) quickly back
111 * to the switch engine. However, when TRYAGAIN=N or TRYAGAIN=forever is
112 * not explicitly set by the admin in the conf file, we want the old "resolver
113 * retry a few times" rather than no retries at all.
114 */
115 static int dns_tryagain_retry = 3;
116
117 /*
118 * For backward compat (pre "lookup control"), the dns default behavior is
119 * soft lookup.
120 */
121 static void
set_dns_default_lkp(struct __nsw_lookup_v1 * lkp)122 set_dns_default_lkp(struct __nsw_lookup_v1 *lkp)
123 {
124 if (strcasecmp(lkp->service_name, "dns") == 0) {
125 lkp->actions[__NSW_TRYAGAIN] = __NSW_TRYAGAIN_NTIMES;
126 lkp->max_retries = dns_tryagain_retry;
127 }
128 }
129
130 /*
131 * Private interface used by nss_common.c, hence this function is not static
132 */
133 struct __nsw_switchconfig_v1 *
_nsw_getoneconfig_v1(const char * name,char * linep,enum __nsw_parse_err * errp)134 _nsw_getoneconfig_v1(const char *name, char *linep, enum __nsw_parse_err *errp)
135 /* linep Nota Bene: not const char * */
136 /* errp Meanings are abused a bit */
137 {
138 struct __nsw_switchconfig_v1 *cfp;
139 struct __nsw_lookup_v1 *lkp, **lkq;
140 int end_crit, dup_fail = 0;
141 action_t act;
142 char *p, *tokenp;
143
144 *errp = __NSW_CONF_PARSE_SUCCESS;
145
146 if ((cfp = libc_malloc(sizeof (struct __nsw_switchconfig_v1)))
147 == NULL) {
148 *errp = __NSW_CONF_PARSE_SYSERR;
149 return (NULL);
150 }
151 LIBC_STRDUP(cfp->dbase, name);
152 lkq = &cfp->lookups;
153
154 /* linep points to a naming service name */
155 for (;;) {
156 int i;
157
158 /* white space following the last service */
159 if (*linep == '\0' || *linep == '\n') {
160 return (cfp);
161 }
162 if ((lkp = libc_malloc(sizeof (struct __nsw_lookup_v1)))
163 == NULL) {
164 *errp = __NSW_CONF_PARSE_SYSERR;
165 freeconf_v1(cfp);
166 return (NULL);
167 }
168
169 *lkq = lkp;
170 lkq = &lkp->next;
171
172 for (i = 0; i < __NSW_STD_ERRS_V1; i++)
173 if (i == __NSW_SUCCESS)
174 lkp->actions[i] = __NSW_RETURN;
175 else if (i == __NSW_TRYAGAIN)
176 lkp->actions[i] = __NSW_TRYAGAIN_FOREVER;
177 else
178 lkp->actions[i] = __NSW_CONTINUE;
179
180 /* get criteria for the naming service */
181 if (tokenp = skip(&linep, '[')) { /* got criteria */
182
183 /* premature end, illegal char following [ */
184 if (!islabel(*linep))
185 goto barf_line;
186 LIBC_STRDUP(lkp->service_name, tokenp);
187 cfp->num_lookups++;
188
189 set_dns_default_lkp(lkp);
190
191 end_crit = 0;
192
193 /* linep points to a switch_err */
194 for (;;) {
195 int ntimes = 0; /* try again max N times */
196 int dns_continue = 0;
197
198 if ((tokenp = skip(&linep, '=')) == NULL) {
199 goto barf_line;
200 }
201
202 /* premature end, ill char following = */
203 if (!islabel(*linep))
204 goto barf_line;
205
206 /* linep points to the string following '=' */
207 p = labelskip(linep);
208 if (*p == ']')
209 end_crit = 1;
210 else if (*p != ' ' && *p != '\t')
211 goto barf_line;
212 *p++ = '\0'; /* null terminate linep */
213 p = spaceskip(p);
214 if (!end_crit) {
215 if (*p == ']') {
216 end_crit = 1;
217 *p++ = '\0';
218 } else if (*p == '\0' || *p == '\n') {
219 return (cfp);
220 } else if (!islabel(*p))
221 /* p better be the next switch_err */
222 goto barf_line;
223 }
224 if (strcasecmp(linep, __NSW_STR_RETURN) == 0)
225 act = __NSW_RETURN;
226 else if (strcasecmp(linep,
227 __NSW_STR_CONTINUE) == 0) {
228 if (strcasecmp(lkp->service_name,
229 "dns") == 0 &&
230 strcasecmp(tokenp,
231 __NSW_STR_TRYAGAIN)
232 == 0) {
233 /*
234 * Add one more condition
235 * so it retries only if it's
236 * "dns [TRYAGAIN=continue]"
237 */
238 dns_continue = 1;
239 act = __NSW_TRYAGAIN_NTIMES;
240 } else
241 act = __NSW_CONTINUE;
242 } else if (strcasecmp(linep,
243 __NSW_STR_FOREVER) == 0)
244 act = __NSW_TRYAGAIN_FOREVER;
245 else if (alldigits(linep)) {
246 act = __NSW_TRYAGAIN_NTIMES;
247 ntimes = atoi(linep);
248 if (ntimes < 0 || ntimes > INT_MAX)
249 ntimes = 0;
250 }
251 else
252 goto barf_line;
253
254 if (__NSW_SUCCESS_ACTION(act) &&
255 strcasecmp(tokenp,
256 __NSW_STR_SUCCESS) == 0) {
257 lkp->actions[__NSW_SUCCESS] = act;
258 } else if (__NSW_NOTFOUND_ACTION(act) &&
259 strcasecmp(tokenp,
260 __NSW_STR_NOTFOUND) == 0) {
261 lkp->actions[__NSW_NOTFOUND] = act;
262 } else if (__NSW_UNAVAIL_ACTION(act) &&
263 strcasecmp(tokenp,
264 __NSW_STR_UNAVAIL) == 0) {
265 lkp->actions[__NSW_UNAVAIL] = act;
266 } else if (__NSW_TRYAGAIN_ACTION(act) &&
267 strcasecmp(tokenp,
268 __NSW_STR_TRYAGAIN) == 0) {
269 lkp->actions[__NSW_TRYAGAIN] = act;
270 if (strcasecmp(lkp->service_name,
271 "nis") == 0)
272 lkp->actions[
273 __NSW_NISSERVDNS_TRYAGAIN]
274 = act;
275 if (act == __NSW_TRYAGAIN_NTIMES)
276 lkp->max_retries =
277 dns_continue ?
278 dns_tryagain_retry : ntimes;
279 } else {
280 /*EMPTY*/
281 /*
282 * convert string tokenp to integer
283 * and put in long_errs
284 */
285 }
286 if (end_crit) {
287 linep = spaceskip(p);
288 if (*linep == '\0' || *linep == '\n')
289 return (cfp);
290 break; /* process next naming service */
291 }
292 linep = p;
293 } /* end of while loop for a name service's criteria */
294 } else {
295 /*
296 * no criteria for this naming service.
297 * linep points to name service, but not null
298 * terminated.
299 */
300 p = labelskip(linep);
301 if (*p == '\0' || *p == '\n') {
302 *p = '\0';
303 LIBC_STRDUP(lkp->service_name, linep);
304 set_dns_default_lkp(lkp);
305 cfp->num_lookups++;
306 return (cfp);
307 }
308 if (*p != ' ' && *p != '\t')
309 goto barf_line;
310 *p++ = '\0';
311 LIBC_STRDUP(lkp->service_name, linep);
312 set_dns_default_lkp(lkp);
313 cfp->num_lookups++;
314 linep = spaceskip(p);
315 }
316 } /* end of while(1) loop for a name service */
317
318 barf_line:
319 freeconf_v1(cfp);
320 *errp = dup_fail ? __NSW_CONF_PARSE_SYSERR : __NSW_CONF_PARSE_NOPOLICY;
321 return (NULL);
322 }
323
324 /*
325 * Private interface used by nss_common.c, hence this function is not static
326 */
327 struct __nsw_switchconfig *
_nsw_getoneconfig(const char * name,char * linep,enum __nsw_parse_err * errp)328 _nsw_getoneconfig(const char *name, char *linep, enum __nsw_parse_err *errp)
329 /* linep Nota Bene: not const char * */
330 /* errp Meanings are abused a bit */
331 {
332 struct __nsw_switchconfig *cfp;
333 struct __nsw_lookup *lkp, **lkq;
334 int end_crit, dup_fail = 0;
335 action_t act;
336 char *p, *tokenp;
337
338 *errp = __NSW_CONF_PARSE_SUCCESS;
339
340 if ((cfp = libc_malloc(sizeof (struct __nsw_switchconfig)))
341 == NULL) {
342 *errp = __NSW_CONF_PARSE_SYSERR;
343 return (NULL);
344 }
345 LIBC_STRDUP(cfp->dbase, name);
346 lkq = &cfp->lookups;
347
348 /* linep points to a naming service name */
349 for (;;) {
350 int i;
351
352 /* white space following the last service */
353 if (*linep == '\0' || *linep == '\n') {
354 return (cfp);
355 }
356 if ((lkp = libc_malloc(sizeof (struct __nsw_lookup)))
357 == NULL) {
358 *errp = __NSW_CONF_PARSE_SYSERR;
359 freeconf(cfp);
360 return (NULL);
361 }
362
363 *lkq = lkp;
364 lkq = &lkp->next;
365
366 for (i = 0; i < __NSW_STD_ERRS; i++)
367 if (i == __NSW_SUCCESS)
368 lkp->actions[i] = 1;
369 else
370 lkp->actions[i] = 0;
371
372 /* get criteria for the naming service */
373 if (tokenp = skip(&linep, '[')) { /* got criteria */
374
375 /* premature end, illegal char following [ */
376 if (!islabel(*linep))
377 goto barf_line;
378 LIBC_STRDUP(lkp->service_name, tokenp);
379 cfp->num_lookups++;
380 end_crit = 0;
381
382 /* linep points to a switch_err */
383 for (;;) {
384 if ((tokenp = skip(&linep, '=')) == NULL) {
385 goto barf_line;
386 }
387
388 /* premature end, ill char following = */
389 if (!islabel(*linep))
390 goto barf_line;
391
392 /* linep points to the string following '=' */
393 p = labelskip(linep);
394 if (*p == ']')
395 end_crit = 1;
396 else if (*p != ' ' && *p != '\t')
397 goto barf_line;
398 *p++ = '\0'; /* null terminate linep */
399 p = spaceskip(p);
400 if (!end_crit) {
401 if (*p == ']') {
402 end_crit = 1;
403 *p++ = '\0';
404 } else if (*p == '\0' || *p == '\n')
405 return (cfp);
406 else if (!islabel(*p))
407 /* p better be the next switch_err */
408 goto barf_line;
409 }
410 if (strcasecmp(linep, __NSW_STR_RETURN) == 0)
411 act = __NSW_RETURN;
412 else if (strcasecmp(linep,
413 __NSW_STR_CONTINUE) == 0)
414 act = __NSW_CONTINUE;
415 else if (strcasecmp(linep,
416 __NSW_STR_FOREVER) == 0)
417 /*
418 * =forever or =N might be in conf file
419 * but old progs won't expect it.
420 */
421 act = __NSW_RETURN;
422 else if (alldigits(linep))
423 act = __NSW_CONTINUE;
424 else
425 goto barf_line;
426 if (strcasecmp(tokenp,
427 __NSW_STR_SUCCESS) == 0) {
428 lkp->actions[__NSW_SUCCESS] = act;
429 } else if (strcasecmp(tokenp,
430 __NSW_STR_NOTFOUND) == 0) {
431 lkp->actions[__NSW_NOTFOUND] = act;
432 } else if (strcasecmp(tokenp,
433 __NSW_STR_UNAVAIL) == 0) {
434 lkp->actions[__NSW_UNAVAIL] = act;
435 } else if (strcasecmp(tokenp,
436 __NSW_STR_TRYAGAIN) == 0) {
437 lkp->actions[__NSW_TRYAGAIN] = act;
438 } else {
439 /*EMPTY*/
440 /*
441 * convert string tokenp to integer
442 * and put in long_errs
443 */
444 }
445 if (end_crit) {
446 linep = spaceskip(p);
447 if (*linep == '\0' || *linep == '\n')
448 return (cfp);
449 break; /* process next naming service */
450 }
451 linep = p;
452 } /* end of while loop for a name service's criteria */
453 } else {
454 /*
455 * no criteria for this naming service.
456 * linep points to name service, but not null
457 * terminated.
458 */
459 p = labelskip(linep);
460 if (*p == '\0' || *p == '\n') {
461 *p = '\0';
462 LIBC_STRDUP(lkp->service_name, linep);
463 cfp->num_lookups++;
464 return (cfp);
465 }
466 if (*p != ' ' && *p != '\t')
467 goto barf_line;
468 *p++ = '\0';
469 LIBC_STRDUP(lkp->service_name, linep);
470 cfp->num_lookups++;
471 linep = spaceskip(p);
472 }
473 } /* end of while(1) loop for a name service */
474
475 barf_line:
476 freeconf(cfp);
477 *errp = dup_fail ? __NSW_CONF_PARSE_SYSERR : __NSW_CONF_PARSE_NOPOLICY;
478 return (NULL);
479 }
480
481 static mutex_t serialize_config_v1 = DEFAULTMUTEX;
482 static mutex_t serialize_config = DEFAULTMUTEX;
483
484 static void
syslog_warning(const char * dbase)485 syslog_warning(const char *dbase)
486 {
487 syslog(LOG_WARNING,
488 "libc: bad lookup policy for %s in %s, using defaults..\n",
489 dbase, __NSW_CONFIG_FILE);
490 }
491
492 /*
493 * Since we cannot call malloc() or lock any of the ordinary mutexes
494 * while we hold an lmutex_lock(), we open the file outside the lock
495 * and disable locking on the file; the latter is fine because we're
496 * reading the fp only from a single thread.
497 */
498 static FILE *
open_conf(void)499 open_conf(void)
500 {
501 FILE *fp = fopen(__NSW_CONFIG_FILE, "rF");
502
503 if (fp != NULL) {
504 if (_findbuf(fp) == NULL) {
505 (void) fclose(fp);
506 return (NULL);
507 }
508 SET_IONOLOCK(fp);
509 }
510 return (fp);
511 }
512
513 struct __nsw_switchconfig_v1 *
__nsw_getconfig_v1(const char * dbase,enum __nsw_parse_err * errp)514 __nsw_getconfig_v1(const char *dbase, enum __nsw_parse_err *errp)
515 {
516 struct __nsw_switchconfig_v1 *cfp, *retp = NULL;
517 int syslog_error = 0;
518 FILE *fp = NULL;
519 char *linep;
520 char lineq[BUFSIZ];
521
522 lmutex_lock(&serialize_config_v1);
523 top:
524 if (cfp = scrounge_cache_v1(dbase)) {
525 *errp = __NSW_CONF_PARSE_SUCCESS;
526 lmutex_unlock(&serialize_config_v1);
527 if (fp != NULL)
528 (void) fclose(fp);
529 return (cfp);
530 }
531
532 if (fp == NULL) {
533 struct cons_cell_v1 *cp = concell_list_v1;
534
535 lmutex_unlock(&serialize_config_v1);
536 /* open_conf() must be called w/o locks held */
537 if ((fp = open_conf()) == NULL) {
538 *errp = __NSW_CONF_PARSE_NOFILE;
539 return (NULL);
540 }
541 lmutex_lock(&serialize_config_v1);
542 /* Cache changed? */
543 if (cp != concell_list_v1)
544 goto top;
545 }
546
547 *errp = __NSW_CONF_PARSE_NOPOLICY;
548 while (linep = fgets(lineq, BUFSIZ, fp)) {
549 enum __nsw_parse_err line_err;
550 char *tokenp, *comment;
551
552 /*
553 * Ignore portion of line following the comment character '#'.
554 */
555 if ((comment = strchr(linep, '#')) != NULL) {
556 *comment = '\0';
557 }
558 /*
559 * skip past blank lines.
560 * otherwise, cache as a struct switchconfig.
561 */
562 if ((*linep == '\0') || isspace(*linep)) {
563 continue;
564 }
565 if ((tokenp = skip(&linep, ':')) == NULL) {
566 continue; /* ignore this line */
567 }
568 if (cfp = scrounge_cache_v1(tokenp)) {
569 continue; /* ? somehow this database is in the cache */
570 }
571 if (cfp = _nsw_getoneconfig_v1(tokenp, linep, &line_err)) {
572 (void) add_concell_v1(cfp);
573 if (strcmp(cfp->dbase, dbase) == 0) {
574 *errp = __NSW_CONF_PARSE_SUCCESS;
575 retp = cfp;
576 }
577 } else {
578 /*
579 * Got an error on this line, if it is a system
580 * error we might as well give right now. If it
581 * is a parse error on the second entry of the
582 * database we are looking for and the first one
583 * was a good entry we end up logging the following
584 * syslog message and using a default policy instead.
585 */
586 if (line_err == __NSW_CONF_PARSE_SYSERR) {
587 *errp = __NSW_CONF_PARSE_SYSERR;
588 break;
589 } else if (line_err == __NSW_CONF_PARSE_NOPOLICY &&
590 strcmp(tokenp, dbase) == 0) {
591 syslog_error = 1;
592 *errp = __NSW_CONF_PARSE_NOPOLICY;
593 break;
594 }
595 /*
596 * Else blithely ignore problems on this line and
597 * go ahead with the next line.
598 */
599 }
600 }
601 lmutex_unlock(&serialize_config_v1);
602 /*
603 * We have to drop the lock before calling fclose()/syslog().
604 */
605 (void) fclose(fp);
606 if (syslog_error)
607 syslog_warning(dbase);
608 return (retp);
609 }
610
611 struct __nsw_switchconfig *
__nsw_getconfig(const char * dbase,enum __nsw_parse_err * errp)612 __nsw_getconfig(const char *dbase, enum __nsw_parse_err *errp)
613 {
614 struct __nsw_switchconfig *cfp, *retp = NULL;
615 int syslog_error = 0;
616 FILE *fp = NULL;
617 char *linep;
618 char lineq[BUFSIZ];
619
620 lmutex_lock(&serialize_config);
621 top:
622 if (cfp = scrounge_cache(dbase)) {
623 *errp = __NSW_CONF_PARSE_SUCCESS;
624 lmutex_unlock(&serialize_config);
625 if (fp != NULL)
626 (void) fclose(fp);
627 return (cfp);
628 }
629
630 if (fp == NULL) {
631 struct cons_cell *cp = concell_list;
632 /* open_conf() must be called w/o locks held */
633 lmutex_unlock(&serialize_config);
634 if ((fp = open_conf()) == NULL) {
635 *errp = __NSW_CONF_PARSE_NOFILE;
636 return (NULL);
637 }
638 lmutex_lock(&serialize_config);
639 /* Cache changed? */
640 if (cp != concell_list)
641 goto top;
642 }
643
644 *errp = __NSW_CONF_PARSE_NOPOLICY;
645 while (linep = fgets(lineq, BUFSIZ, fp)) {
646 enum __nsw_parse_err line_err;
647 char *tokenp, *comment;
648
649 /*
650 * Ignore portion of line following the comment character '#'.
651 */
652 if ((comment = strchr(linep, '#')) != NULL) {
653 *comment = '\0';
654 }
655 /*
656 * skip past blank lines.
657 * otherwise, cache as a struct switchconfig.
658 */
659 if ((*linep == '\0') || isspace(*linep)) {
660 continue;
661 }
662 if ((tokenp = skip(&linep, ':')) == NULL) {
663 continue; /* ignore this line */
664 }
665 if (cfp = scrounge_cache(tokenp)) {
666 continue; /* ? somehow this database is in the cache */
667 }
668 if (cfp = _nsw_getoneconfig(tokenp, linep, &line_err)) {
669 (void) add_concell(cfp);
670 if (strcmp(cfp->dbase, dbase) == 0) {
671 *errp = __NSW_CONF_PARSE_SUCCESS;
672 retp = cfp;
673 }
674 } else {
675 /*
676 * Got an error on this line, if it is a system
677 * error we might as well give right now. If it
678 * is a parse error on the second entry of the
679 * database we are looking for and the first one
680 * was a good entry we end up logging the following
681 * syslog message and using a default policy instead.
682 */
683 if (line_err == __NSW_CONF_PARSE_SYSERR) {
684 *errp = __NSW_CONF_PARSE_SYSERR;
685 break;
686 } else if (line_err == __NSW_CONF_PARSE_NOPOLICY &&
687 strcmp(tokenp, dbase) == 0) {
688 syslog_error = 1;
689 *errp = __NSW_CONF_PARSE_NOPOLICY;
690 break;
691 }
692 /*
693 * Else blithely ignore problems on this line and
694 * go ahead with the next line.
695 */
696 }
697 }
698 lmutex_unlock(&serialize_config);
699 /*
700 * We have to drop the lock before calling fclose()/syslog().
701 */
702 (void) fclose(fp);
703 if (syslog_error)
704 syslog_warning(dbase);
705 return (retp);
706 }
707
708
709 static struct __nsw_switchconfig_v1 *
scrounge_cache_v1(const char * dbase)710 scrounge_cache_v1(const char *dbase)
711 {
712 struct cons_cell_v1 *cellp = concell_list_v1;
713
714 for (; cellp; cellp = cellp->next)
715 if (strcmp(dbase, cellp->sw->dbase) == 0)
716 return (cellp->sw);
717 return (NULL);
718 }
719
720 static struct __nsw_switchconfig *
scrounge_cache(const char * dbase)721 scrounge_cache(const char *dbase)
722 {
723 struct cons_cell *cellp = concell_list;
724
725 for (; cellp; cellp = cellp->next)
726 if (strcmp(dbase, cellp->sw->dbase) == 0)
727 return (cellp->sw);
728 return (NULL);
729 }
730
731 static void
freeconf_v1(struct __nsw_switchconfig_v1 * cfp)732 freeconf_v1(struct __nsw_switchconfig_v1 *cfp)
733 {
734 if (cfp) {
735 if (cfp->dbase)
736 libc_free(cfp->dbase);
737 if (cfp->lookups) {
738 struct __nsw_lookup_v1 *nex, *cur;
739 for (cur = cfp->lookups; cur; cur = nex) {
740 libc_free(cur->service_name);
741 nex = cur->next;
742 libc_free(cur);
743 }
744 }
745 libc_free(cfp);
746 }
747 }
748
749 static void
freeconf(struct __nsw_switchconfig * cfp)750 freeconf(struct __nsw_switchconfig *cfp)
751 {
752 if (cfp) {
753 if (cfp->dbase)
754 libc_free(cfp->dbase);
755 if (cfp->lookups) {
756 struct __nsw_lookup *nex, *cur;
757 for (cur = cfp->lookups; cur; cur = nex) {
758 libc_free(cur->service_name);
759 nex = cur->next;
760 libc_free(cur);
761 }
762 }
763 libc_free(cfp);
764 }
765 }
766
767 action_t
__nsw_extended_action_v1(struct __nsw_lookup_v1 * lkp,int err)768 __nsw_extended_action_v1(struct __nsw_lookup_v1 *lkp, int err)
769 {
770 struct __nsw_long_err *lerrp;
771
772 for (lerrp = lkp->long_errs; lerrp; lerrp = lerrp->next) {
773 if (lerrp->nsw_errno == err)
774 return (lerrp->action);
775 }
776 return (__NSW_CONTINUE);
777 }
778
779 action_t
__nsw_extended_action(struct __nsw_lookup * lkp,int err)780 __nsw_extended_action(struct __nsw_lookup *lkp, int err)
781 {
782 struct __nsw_long_err *lerrp;
783
784 for (lerrp = lkp->long_errs; lerrp; lerrp = lerrp->next) {
785 if (lerrp->nsw_errno == err)
786 return (lerrp->action);
787 }
788 return (__NSW_CONTINUE);
789 }
790
791
792 /* give the next non-alpha character */
793 static char *
labelskip(char * cur)794 labelskip(char *cur)
795 {
796 char *p = cur;
797 while (islabel(*p))
798 ++p;
799 return (p);
800 }
801
802 /* give the next non-space character */
803 static char *
spaceskip(char * cur)804 spaceskip(char *cur)
805 {
806 char *p = cur;
807 while (*p == ' ' || *p == '\t')
808 ++p;
809 return (p);
810 }
811
812 /*
813 * terminate the *cur pointed string by null only if it is
814 * followed by "key" surrounded by zero or more spaces and
815 * return value is the same as the original *cur pointer and
816 * *cur pointer is advanced to the first non {space, key} char
817 * followed by the key. Otherwise, return NULL and keep
818 * *cur unchanged.
819 */
820 static char *
skip(char ** cur,char key)821 skip(char **cur, char key)
822 {
823 char *p, *tmp;
824 char *q = *cur;
825 int found, tmpfound;
826
827 tmp = labelskip(*cur);
828 p = tmp;
829 found = (*p == key);
830 if (found) {
831 *p++ = '\0'; /* overwrite the key */
832 p = spaceskip(p);
833 } else {
834 while (*p == ' ' || *p == '\t') {
835 tmpfound = (*++p == key);
836 if (tmpfound) {
837 found = tmpfound;
838 /* null terminate the return token */
839 *tmp = '\0';
840 p++; /* skip the key */
841 }
842 }
843 }
844 if (!found)
845 return (NULL); /* *cur unchanged */
846 *cur = p;
847 return (q);
848 }
849
850 /* add to the front: LRU */
851 static int
add_concell_v1(struct __nsw_switchconfig_v1 * cfp)852 add_concell_v1(struct __nsw_switchconfig_v1 *cfp)
853 {
854 struct cons_cell_v1 *cp;
855
856 if (cfp == NULL)
857 return (1);
858 if ((cp = libc_malloc(sizeof (struct cons_cell_v1))) == NULL)
859 return (1);
860 cp->sw = cfp;
861 cp->next = concell_list_v1;
862 concell_list_v1 = cp;
863 return (0);
864 }
865
866 /* add to the front: LRU */
867 static int
add_concell(struct __nsw_switchconfig * cfp)868 add_concell(struct __nsw_switchconfig *cfp)
869 {
870 struct cons_cell *cp;
871
872 if (cfp == NULL)
873 return (1);
874 if ((cp = libc_malloc(sizeof (struct cons_cell))) == NULL)
875 return (1);
876 cp->sw = cfp;
877 cp->next = concell_list;
878 concell_list = cp;
879 return (0);
880 }
881
882 int
__nsw_freeconfig_v1(struct __nsw_switchconfig_v1 * conf)883 __nsw_freeconfig_v1(struct __nsw_switchconfig_v1 *conf)
884 {
885 struct cons_cell_v1 *cellp;
886
887 if (conf == NULL) {
888 return (-1);
889 }
890 /*
891 * Hacked to make life easy for the code in nss_common.c. Free conf
892 * iff it was created by calling _nsw_getoneconfig() directly
893 * rather than by calling nsw_getconfig.
894 */
895 lmutex_lock(&serialize_config_v1);
896 for (cellp = concell_list_v1; cellp; cellp = cellp->next) {
897 if (cellp->sw == conf) {
898 break;
899 }
900 }
901 lmutex_unlock(&serialize_config_v1);
902 if (cellp == NULL) {
903 /* Not in the cache; free it */
904 freeconf_v1(conf);
905 return (1);
906 } else {
907 /* In the cache; don't free it */
908 return (0);
909 }
910 }
911
912 int
__nsw_freeconfig(struct __nsw_switchconfig * conf)913 __nsw_freeconfig(struct __nsw_switchconfig *conf)
914 {
915 struct cons_cell *cellp;
916
917 if (conf == NULL) {
918 return (-1);
919 }
920 /*
921 * Hacked to make life easy for the code in nss_common.c. Free conf
922 * iff it was created by calling _nsw_getoneconfig() directly
923 * rather than by calling nsw_getconfig.
924 */
925 lmutex_lock(&serialize_config);
926 for (cellp = concell_list; cellp; cellp = cellp->next) {
927 if (cellp->sw == conf) {
928 break;
929 }
930 }
931 lmutex_unlock(&serialize_config);
932 if (cellp == NULL) {
933 /* Not in the cache; free it */
934 freeconf(conf);
935 return (1);
936 } else {
937 /* In the cache; don't free it */
938 return (0);
939 }
940 }
941
942 /* Return 1 if the string contains all digits, else return 0. */
943 static int
alldigits(char * s)944 alldigits(char *s)
945 {
946 for (; *s; s++)
947 if (!isdigit(*s))
948 return (0);
949 return (1);
950 }
951