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 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 * 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 * 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 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 * 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 * 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 * 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 * 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 * 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 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 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 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 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 * 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 * 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 * 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 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 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 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 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 944 alldigits(char *s) 945 { 946 for (; *s; s++) 947 if (!isdigit(*s)) 948 return (0); 949 return (1); 950 } 951