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