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 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 * 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 * 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 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 * 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 * 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 * 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 * 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 * 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 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 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 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 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 * 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 * 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 * 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 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 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 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 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 952 alldigits(char *s) 953 { 954 for (; *s; s++) 955 if (!isdigit(*s)) 956 return (0); 957 return (1); 958 } 959