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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Portions of this source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 #include "mt.h" 38 #include "../rpc/rpc_mt.h" /* for MT declarations only */ 39 #include <rpc/types.h> 40 #include <stdio.h> 41 #include <string.h> 42 #include <ctype.h> 43 #include <rpc/trace.h> 44 #include <netconfig.h> 45 #include <malloc.h> 46 #include <syslog.h> 47 #include "netcspace.h" 48 #include "nsl_stdio_prv.h" 49 50 #define FAILURE (unsigned)(-1) 51 52 /* 53 * Local routines used by the library procedures 54 */ 55 56 static int blank(); 57 static int comment(); 58 static struct netconfig *fgetnetconfig(); 59 static void netconfig_free(); 60 static unsigned int getflag(); 61 static char **getlookups(); 62 static struct netconfig **getnetlist(); 63 static unsigned int getnlookups(); 64 static char *gettoken(); 65 static unsigned int getvalue(); 66 static void shift1left(); 67 static void netlist_free(); 68 static void free_entry(); 69 static struct netconfig *netconfig_dup(); 70 71 /* 72 * System V routines used by the library procedures. 73 */ 74 extern char *getenv(); 75 76 /* messaging stuff. */ 77 78 extern const char __nsl_dom[]; 79 extern char *dgettext(const char *, const char *); 80 81 /* 82 * Static global variables used by the library procedures: 83 * 84 * netpp - points to the beginning of the list of netconfig 85 * entries used by setnetconfig() and setnetpath(). 86 * Once netpp is initialized, that memory is *never* 87 * released. This was necessary to improve performance. 88 * 89 * linenum - the current line number of the /etc/netconfig 90 * file (used for debugging and for nc_perror()). 91 * 92 * fieldnum - the current field number of the current line 93 * of /etc/netconfig (used for debugging and for 94 * nc_perror()). 95 * 96 * nc_error - the error condition encountered. 97 */ 98 99 static struct netconfig **netpp = NULL; 100 mutex_t netpp_mutex = DEFAULTMUTEX; 101 /* 102 * The following two variables are used by the /etc/netconfig parsing 103 * routines, which will always be executed once, and within the netpp_mutex. 104 * They are global to allow the nc_sperror routine to provide better 105 * information to the user about /etc/netconfig file problems. 106 */ 107 static int linenum = 0; /* "owned" by getnetlist() */ 108 static int fieldnum = 0; /* "owned" by fgetnetconfig() */ 109 110 111 static int * 112 __nc_error() 113 { 114 static pthread_key_t nc_error_key = 0; 115 static int nc_error = NC_NOERROR; 116 int *ret; 117 118 if (thr_main()) 119 return (&nc_error); 120 ret = thr_get_storage(&nc_error_key, sizeof (int), free); 121 /* if thr_get_storage fails we return the address of nc_error */ 122 return (ret ? ret : &nc_error); 123 } 124 #define nc_error (*(__nc_error())) 125 126 /* 127 * setnetconfig() has the effect of "initializing" the 128 * network configuration database. It reads in the 129 * netcf entries (if not already read in). 130 */ 131 132 void * 133 setnetconfig() 134 { 135 NCONF_HANDLE *retp; 136 137 trace1(TR_setnetconfig, 0); 138 mutex_lock(&netpp_mutex); 139 if ((netpp == NULL) && ((netpp = getnetlist()) == NULL)) { 140 mutex_unlock(&netpp_mutex); 141 trace1(TR_setnetconfig, 1); 142 return (NULL); 143 } 144 mutex_unlock(&netpp_mutex); 145 if ((retp = (NCONF_HANDLE *) malloc(sizeof (NCONF_HANDLE))) == NULL) { 146 nc_error = NC_NOMEM; 147 trace1(TR_setnetconfig, 1); 148 return (NULL); 149 } 150 nc_error = NC_NOERROR; 151 retp->nc_head = retp->nc_curr = netpp; 152 trace1(TR_setnetconfig, 1); 153 return ((void *)retp); 154 } 155 156 /* 157 * endnetconfig() frees up all data allocated by setnetconfig() 158 */ 159 160 int 161 endnetconfig(vdata) 162 void *vdata; 163 { 164 NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata; 165 166 trace1(TR_endnetconfig, 0); 167 mutex_lock(&netpp_mutex); 168 if (netpp == NULL || nconf_handlep == NULL) { 169 nc_error = NC_NOSET; 170 mutex_unlock(&netpp_mutex); 171 trace1(TR_endnetconfig, 1); 172 return (-1); 173 } 174 mutex_unlock(&netpp_mutex); 175 176 nc_error = NC_NOERROR; 177 free((void *)nconf_handlep); 178 trace1(TR_endnetconfig, 1); 179 return (0); 180 } 181 182 /* 183 * getnetconfig() returns the current entry in the list 184 * of netconfig structures. It uses the nconf_handlep argument 185 * to determine the current entry. If setnetconfig() was not 186 * called previously to set up the list, return failure. 187 * It also check if ipv6 interface is present(ipv6_present) and 188 * skips udp6 & tcp6 entries if ipv6 is not supported. 189 */ 190 191 struct netconfig * 192 getnetconfig(vdata) 193 void *vdata; 194 { 195 NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata; 196 struct netconfig *retp; /* holds the return value */ 197 int ipv6_present = -1; 198 199 trace1(TR_getnetconfig, 0); 200 mutex_lock(&netpp_mutex); 201 if ((netpp == NULL) || (nconf_handlep == NULL)) { 202 nc_error = NC_NOSET; 203 mutex_unlock(&netpp_mutex); 204 trace1(TR_getnetconfig, 1); 205 return (NULL); 206 } 207 mutex_unlock(&netpp_mutex); 208 for (;;) { 209 retp = *(nconf_handlep->nc_curr); 210 if (retp && (strcmp(retp->nc_netid, "udp6") == 0 || 211 strcmp(retp->nc_netid, "tcp6") == 0)) { 212 if (ipv6_present == -1) 213 ipv6_present = __can_use_af(AF_INET6); 214 if (!ipv6_present) { 215 ++(nconf_handlep->nc_curr); 216 continue; 217 } 218 } 219 break; 220 } 221 if (retp != NULL) { 222 ++(nconf_handlep->nc_curr); 223 nc_error = NC_NOERROR; 224 } else { 225 nc_error = NC_NOMOREENTRIES; 226 } 227 trace1(TR_getnetconfig, 1); 228 return (retp); 229 } 230 231 /* 232 * getnetconfig() searches the netconfig database for a 233 * given network id. Returns a pointer to the netconfig 234 * structure or a NULL if not found. 235 * It also check if ipv6 interface is present(ipv6_present) and 236 * skips udp6 & tcp6 entries if ipv6 is not supported. 237 */ 238 239 struct netconfig * 240 getnetconfigent(netid) 241 const char *netid; 242 { 243 struct netconfig **tpp; 244 int ipv6_present; 245 246 trace1(TR_getnetconfigent, 0); 247 mutex_lock(&netpp_mutex); 248 if ((netpp == NULL) && ((netpp = getnetlist()) == NULL)) { 249 mutex_unlock(&netpp_mutex); 250 trace1(TR_getnetconfigent, 1); 251 return (NULL); 252 } 253 mutex_unlock(&netpp_mutex); 254 for (tpp = netpp; *tpp; tpp++) { 255 if (strcmp((*tpp)->nc_netid, netid) == 0) { 256 if (*tpp && (strcmp((*tpp)->nc_netid, "udp6") == 0 || 257 strcmp((*tpp)->nc_netid, "tcp6") == 0)) { 258 ipv6_present = __can_use_af(AF_INET6); 259 if (!ipv6_present) { 260 nc_error = NC_NOTFOUND; 261 trace1(TR_getnetconfigent, 1); 262 return (NULL); 263 } 264 } 265 trace1(TR_getnetconfigent, 1); 266 return (netconfig_dup(*tpp)); 267 } 268 } 269 nc_error = NC_NOTFOUND; 270 trace1(TR_getnetconfigent, 1); 271 return (NULL); 272 } 273 274 /* 275 * freenetconfigent frees the data allocated by getnetconfigent() 276 */ 277 278 void 279 freenetconfigent(netp) 280 struct netconfig *netp; 281 { 282 trace1(TR_freenetconfigent, 0); 283 netconfig_free(netp); 284 trace1(TR_freenetconfigent, 1); 285 } 286 287 /* 288 * getnetlist() reads the netconfig file and creates a 289 * NULL-terminated list of entries. 290 * Returns the pointer to the head of the list or a NULL 291 * on failure. 292 */ 293 294 static struct netconfig ** 295 getnetlist() 296 { 297 char line[BUFSIZ]; /* holds each line of NETCONFIG */ 298 __NSL_FILE *fp; /* file stream for NETCONFIG */ 299 struct netconfig **listpp; /* the beginning of the netconfig list */ 300 struct netconfig **tpp; /* used to traverse the netconfig list */ 301 int count; /* the number of entries in file */ 302 303 trace1(TR_getnetlist, 0); 304 if ((fp = __nsl_fopen(NETCONFIG, "r")) == NULL) { 305 nc_error = NC_OPENFAIL; 306 trace1(TR_getnetlist, 1); 307 return (NULL); 308 } 309 310 count = 0; 311 while (__nsl_fgets(line, BUFSIZ, fp)) { 312 if (!(blank(line) || comment(line))) { 313 ++count; 314 } 315 } 316 __nsl_rewind(fp); 317 318 if (count == 0) { 319 nc_error = NC_NOTFOUND; 320 (void) __nsl_fclose(fp); 321 trace1(TR_getnetlist, 1); 322 return (NULL); 323 } 324 if ((listpp = (struct netconfig **)malloc((count + 1) * 325 sizeof (struct netconfig *))) == NULL) { 326 nc_error = NC_NOMEM; 327 (void) __nsl_fclose(fp); 328 trace1(TR_getnetlist, 1); 329 return (NULL); 330 } 331 332 /* 333 * The following loop fills in the list (loops until 334 * fgetnetconfig() returns a NULL) and counts the 335 * number of entries placed in the list. Note that 336 * when the loop is completed, the last entry in the 337 * list will contain a NULL (signifying the end of 338 * the list). 339 */ 340 linenum = 0; 341 for (tpp = listpp; *tpp = fgetnetconfig(fp, NULL); tpp++) 342 ; 343 (void) __nsl_fclose(fp); 344 345 if (nc_error != NC_NOMOREENTRIES) /* Something is screwed up */ 346 netlist_free(&listpp); 347 trace1(TR_getnetlist, 1); 348 return (listpp); 349 } 350 351 /* 352 * fgetnetconfig() parses a line of the netconfig file into 353 * a netconfig structure. It returns a pointer to the 354 * structure of success and a NULL on failure or EOF. 355 */ 356 357 static struct netconfig * 358 fgetnetconfig(fp, netid) 359 __NSL_FILE *fp; 360 char *netid; 361 { 362 char linep[BUFSIZ]; /* pointer to a line in the file */ 363 struct netconfig *netconfigp; /* holds the new netconfig structure */ 364 char *tok1, *tok2, *tok3; /* holds a token from the line */ 365 char *retvalp; /* the return value of fgets() */ 366 char *entnetid; /* netid for the current entry */ 367 368 trace1(TR_fgetnetconfig, 0); 369 /* skip past blank lines and comments. */ 370 while (retvalp = __nsl_fgets(linep, BUFSIZ, fp)) { 371 linenum++; 372 if (!(blank(linep) || comment(linep))) { 373 break; 374 } 375 retvalp = NULL; 376 } 377 if (retvalp == NULL) { 378 nc_error = NC_NOMOREENTRIES; 379 trace1(TR_fgetnetconfig, 1); 380 return (NULL); 381 } 382 fieldnum = 0; 383 if ((entnetid = gettoken(linep, FALSE)) == NULL) { 384 nc_error = NC_BADLINE; 385 trace1(TR_fgetnetconfig, 1); 386 return (NULL); 387 } 388 if (netid && (strcmp(netid, entnetid) != 0)) { 389 free(entnetid); 390 nc_error = NC_NOTFOUND; 391 trace1(TR_fgetnetconfig, 1); 392 return (NULL); 393 } 394 if ((netconfigp = (struct netconfig *) 395 calloc(1, sizeof (struct netconfig))) == NULL) { 396 free(entnetid); 397 nc_error = NC_NOMEM; 398 trace1(TR_fgetnetconfig, 1); 399 return (NULL); 400 } 401 402 tok1 = tok2 = tok3 = NULL; 403 netconfigp->nc_netid = entnetid; 404 if (((tok1 = gettoken(NULL, FALSE)) == NULL) || 405 ((netconfigp->nc_semantics = 406 getvalue(tok1, nc_semantics)) == FAILURE) || 407 ((tok2 = gettoken(NULL, FALSE)) == NULL) || 408 ((netconfigp->nc_flag = getflag(tok2)) == FAILURE) || 409 ((netconfigp->nc_protofmly = gettoken(NULL, FALSE)) == NULL) || 410 ((netconfigp->nc_proto = gettoken(NULL, FALSE)) == NULL) || 411 ((netconfigp->nc_device = gettoken(NULL, FALSE)) == NULL) || 412 ((tok3 = gettoken(NULL, TRUE)) == NULL) || 413 (((netconfigp->nc_nlookups = getnlookups(tok3)) != 0) && 414 ((netconfigp->nc_lookups = getlookups(tok3)) == NULL))) { 415 netconfig_free(netconfigp); 416 nc_error = NC_BADLINE; 417 netconfigp = NULL; 418 } 419 free(tok1); 420 free(tok2); 421 free(tok3); 422 trace1(TR_fgetnetconfig, 1); 423 return (netconfigp); 424 } 425 426 /* 427 * setnetpath() has the effect of "initializing" the 428 * NETPATH variable. It reads in the netcf entries (if not 429 * already read in), creates a list corresponding to the entries 430 * in the NETPATH variable (or the "visible" entries og netconfig 431 * if NETPATH is not set). 432 */ 433 434 void * 435 setnetpath() 436 { 437 int count; /* the number of entries in NETPATH */ 438 char valid_netpath[BUFSIZ]; /* holds the valid entries if NETPATH */ 439 char templine[BUFSIZ]; /* has value of NETPATH when scanning */ 440 struct netconfig **curr_pp; /* scans the list from NETPATH */ 441 struct netconfig **tpp; /* scans the list from netconfig file */ 442 struct netconfig **rnetpp; /* the list of entries from NETPATH */ 443 char *netpath; /* value of NETPATH from environment */ 444 char *netid; /* holds a component of NETPATH */ 445 char *tp; /* used to scan NETPATH string */ 446 NCONF_HANDLE *retp; /* the return value */ 447 448 trace1(TR_setnetpath, 0); 449 /* 450 * Read in the netconfig database if not already read in 451 */ 452 mutex_lock(&netpp_mutex); 453 if ((netpp == NULL) && ((netpp = getnetlist()) == NULL)) { 454 mutex_unlock(&netpp_mutex); 455 trace1(TR_setnetpath, 1); 456 return (NULL); 457 } 458 mutex_unlock(&netpp_mutex); 459 460 if ((retp = (NCONF_HANDLE *) malloc(sizeof (NCONF_HANDLE))) == NULL) { 461 nc_error = NC_NOMEM; 462 trace1(TR_setnetpath, 1); 463 return (NULL); 464 } 465 466 /* 467 * Get the valid entries of the NETPATH variable (and 468 * count the number of entries while doing it). 469 * 470 * This is done every time the procedure is called just 471 * in case NETPATH has changed from call to call. 472 * 473 * If NETPATH is too long, we ignore it altogether as 474 * it can only be a buffer overflow attack. 475 * Since we add one colon for each entry, but colons only 476 * need to exist between entries, we have to subtract one. 477 */ 478 count = 0; 479 valid_netpath[0] = '\0'; 480 if ((netpath = getenv(NETPATH)) == NULL || 481 strlen(netpath) >= sizeof (templine) - 1) { 482 /* 483 * If NETPATH variable is not set or invalid, 484 * the valid NETPATH consist of all "visible" 485 * netids from the netconfig database. 486 */ 487 488 for (tpp = netpp; *tpp; tpp++) { 489 if ((*tpp)->nc_flag & NC_VISIBLE) { 490 (void) strcat(valid_netpath, (*tpp)->nc_netid); 491 (void) strcat(valid_netpath, ":"); 492 count++; 493 } 494 } 495 } else { 496 497 /* 498 * Copy the value of NETPATH (since '\0's will be 499 * put into the string) and create the valid NETPATH 500 * (by throwing away all netids not in the database). 501 * If an entry appears more than one, it *will* be 502 * listed twice in the list of valid netpath entries. 503 */ 504 505 (void) strcpy(templine, netpath); 506 tp = templine; 507 508 while (*tp) { 509 /* Skip all leading ':'s */ 510 while (*tp && *tp == ':') 511 tp++; 512 if (*tp == NULL) 513 break; /* last one */ 514 netid = tp; 515 while (*tp && *tp != ':') 516 tp++; 517 if (*tp) 518 *tp++ = '\0'; /* isolate netid */ 519 520 for (tpp = netpp; *tpp; tpp++) { 521 if (strcmp(netid, (*tpp)->nc_netid) == 0) { 522 (void) strcat(valid_netpath, 523 (*tpp)->nc_netid); 524 (void) strcat(valid_netpath, ":"); 525 count++; 526 break; 527 } 528 } 529 } 530 } 531 532 /* Get space to hold the valid list (+1 for the NULL) */ 533 534 if ((rnetpp = (struct netconfig **)malloc((count + 1) * 535 sizeof (struct netconfig *))) == NULL) { 536 free((void *) retp); 537 nc_error = NC_NOMEM; 538 trace1(TR_setnetpath, 1); 539 return (NULL); 540 } 541 542 /* 543 * Populate the NETPATH list, ending it with a NULL. 544 * Each entry in the list points to the structure in the 545 * "netpp" list (the entry must exist in the list, otherwise 546 * it wouldn't appear in valid_netpath[]). 547 */ 548 549 curr_pp = rnetpp; 550 netid = tp = valid_netpath; 551 while (*tp) { 552 netid = tp; 553 while (*tp && *tp != ':') 554 tp++; 555 if (*tp) 556 *tp++ = '\0'; 557 for (tpp = netpp; *tpp; tpp++) { 558 if (strcmp(netid, (*tpp)->nc_netid) == 0) { 559 *curr_pp++ = *tpp; 560 break; 561 } 562 } 563 } 564 *curr_pp = NULL; 565 566 retp->nc_curr = retp->nc_head = rnetpp; 567 trace1(TR_setnetpath, 1); 568 return ((void *)retp); 569 } 570 571 /* 572 * endnetpath() frees up all of the memory allocated by setnetpath(). 573 * It returns -1 (error) if setnetpath was never called. 574 */ 575 576 int 577 endnetpath(vdata) 578 void *vdata; 579 { 580 /* The argument is really a NCONF_HANDLE; cast it here */ 581 NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata; 582 583 trace1(TR_endnetpath, 0); 584 mutex_lock(&netpp_mutex); 585 if (netpp == NULL || nconf_handlep == NULL) { 586 nc_error = NC_NOSET; 587 mutex_unlock(&netpp_mutex); 588 trace1(TR_endnetpath, 1); 589 return (-1); 590 } 591 mutex_unlock(&netpp_mutex); 592 593 free(nconf_handlep->nc_head); 594 free(nconf_handlep); 595 trace1(TR_endnetpath, 1); 596 return (0); 597 } 598 599 /* 600 * getnetpath() returns the current entry in the list 601 * from the NETPATH variable. If setnetpath() was not called 602 * previously to set up the list, return NULL. 603 */ 604 605 struct netconfig * 606 getnetpath(vdata) 607 void *vdata; 608 { 609 /* The argument is really a NCONF_HANDLE; cast it here */ 610 NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata; 611 struct netconfig *retp; /* holds the return value */ 612 int ipv6_present = -1; 613 614 trace1(TR_getnetpath, 0); 615 mutex_lock(&netpp_mutex); 616 if (netpp == NULL) { 617 nc_error = NC_NOSET; 618 mutex_unlock(&netpp_mutex); 619 trace1(TR_getnetpath, 1); 620 return (NULL); 621 } 622 mutex_unlock(&netpp_mutex); 623 for (;;) { 624 retp = *(nconf_handlep->nc_curr); 625 if (retp && (strcmp(retp->nc_netid, "udp6") == 0 || 626 strcmp(retp->nc_netid, "tcp6") == 0)) { 627 if (ipv6_present == -1) 628 ipv6_present = __can_use_af(AF_INET6); 629 if (!ipv6_present) { 630 ++(nconf_handlep->nc_curr); 631 continue; 632 } 633 } 634 break; 635 } 636 if (retp) { 637 ++(nconf_handlep->nc_curr); 638 nc_error = NC_NOERROR; 639 } else { 640 nc_error = NC_NOMOREENTRIES; 641 } 642 643 trace1(TR_getnetpath, 1); 644 return (retp); 645 } 646 647 /* 648 * blank() returns true if the line is a blank line, 0 otherwise 649 */ 650 651 static int 652 blank(cp) 653 char *cp; 654 { 655 trace1(TR_blank, 0); 656 while (*cp && isspace(*cp)) { 657 cp++; 658 } 659 trace1(TR_blank, 1); 660 return (*cp == '\0'); 661 } 662 663 /* 664 * comment() returns true if the line is a comment, 0 otherwise. 665 */ 666 667 static int 668 comment(cp) 669 char *cp; 670 { 671 trace1(TR_comment, 0); 672 while (*cp && isspace(*cp)) { 673 cp++; 674 } 675 trace1(TR_comment, 1); 676 return (*cp == '#'); 677 } 678 679 /* 680 * getvalue() searches for the given string in the given array, 681 * and return the integer value associated with the string. 682 */ 683 684 static unsigned int 685 getvalue(cp, nc_data) 686 char *cp; 687 struct nc_data nc_data[]; 688 { 689 int i; /* used to index through the given struct nc_data array */ 690 691 trace1(TR_getvalue, 0); 692 for (i = 0; nc_data[i].string; i++) { 693 if (strcmp(nc_data[i].string, cp) == 0) { 694 break; 695 } 696 } 697 trace1(TR_getvalue, 1); 698 return (nc_data[i].value); 699 } 700 701 /* 702 * getflag() creates a bitmap of the one-character flags in 703 * the given string. It uses nc_flags array to get the values. 704 */ 705 706 static unsigned int 707 getflag(cp) 708 char *cp; 709 { 710 int i; /* indexs through the nc_flag array */ 711 unsigned int mask = 0; /* holds bitmask of flags */ 712 713 trace1(TR_getflag, 0); 714 while (*cp) { 715 for (i = 0; nc_flag[i].string; i++) { 716 if (*nc_flag[i].string == *cp) { 717 mask |= nc_flag[i].value; 718 break; 719 } 720 } 721 cp++; 722 } 723 trace1(TR_getflag, 1); 724 return (mask); 725 } 726 727 /* 728 * getlookups() creates and returns an array of string representing 729 * the directory lookup libraries, given as a comma-seperated list 730 * in the argument "cp". 731 */ 732 733 static char ** 734 getlookups(cp) 735 char *cp; 736 { 737 unsigned int num; /* holds the number of entries in the list */ 738 char **listpp; /* the beginning of the list of dir routines */ 739 char **tpp; /* traverses the list, populating it */ 740 char *start; 741 742 trace1(TR_getlookups, 0); 743 num = getnlookups(cp); 744 if (num == 0) { 745 trace1(TR_getlookups, 1); 746 return (NULL); 747 } 748 if ((listpp = (char **)malloc((num + 1) * sizeof (char *))) == NULL) { 749 trace1(TR_getlookups, 1); 750 return (NULL); 751 } 752 753 tpp = listpp; 754 while (num--) { 755 start = cp; 756 757 /* 758 * Traverse the string looking for the next entry 759 * of the list (i.e, where the ',' or end of the 760 * string appears). If a "\" is found, shift the 761 * token over 1 to the left (taking the next char 762 * literally). 763 */ 764 765 while (*cp && *cp != ',') { 766 if (*cp == '\\' && *(cp + 1)) { 767 shift1left(cp); 768 } 769 cp++; 770 } 771 if (*cp) 772 *cp++ = '\0'; 773 if ((*tpp++ = strdup(start)) == NULL) { 774 for (tpp = listpp; *tpp; tpp++) 775 free(*tpp); 776 free(listpp); 777 trace1(TR_getlookups, 1); 778 return (NULL); 779 } 780 } 781 *tpp = NULL; 782 trace1(TR_getlookups, 1); 783 return (listpp); 784 } 785 786 /* 787 * getnlookups() returns the number of entries in a comma-separated 788 * string of tokens. A "-" means no strings are present. 789 */ 790 791 static unsigned int 792 getnlookups(cp) 793 char *cp; 794 { 795 unsigned int count; /* the number of tokens in the string */ 796 797 trace1(TR_getnlookups, 0); 798 if (strcmp(cp, "-") == 0) { 799 trace1(TR_getnlookups, 1); 800 return (0); 801 } 802 803 count = 1; 804 while (*cp) { 805 if (*cp == ',') { 806 count++; 807 } 808 809 /* 810 * If a "\" is in the string, take the next character 811 * literally. Onlly skip the character if "\" is 812 * not the last character of the token. 813 */ 814 if (*cp == '\\' && *(cp + 1)) { 815 cp++; 816 } 817 cp++; 818 } 819 trace1(TR_getnlookups, 1); 820 return (count); 821 } 822 823 /* 824 * gettoken() behaves much like strtok(), except that 825 * it knows about escaped space characters (i.e., space characters 826 * preceeded by a '\' are taken literally). 827 */ 828 829 static char * 830 gettoken(cp, skip) 831 char *cp; 832 int skip; 833 { 834 static char *savep; /* the place where we left off */ 835 char *p; /* the beginning of the new token */ 836 char *retp; /* the token to be returned */ 837 838 trace1(TR_gettoken, 0); 839 fieldnum++; 840 841 /* Determine if first or subsequent call */ 842 p = (cp == NULL)? savep: cp; 843 844 /* Return if no tokens remain. */ 845 if (p == 0) { 846 trace1(TR_gettoken, 1); 847 return (NULL); 848 } 849 850 while (isspace(*p)) 851 p++; 852 853 if (*p == '\0') { 854 trace1(TR_gettoken, 1); 855 return (NULL); 856 } 857 858 /* 859 * Save the location of the token and then skip past it 860 */ 861 862 retp = p; 863 while (*p) { 864 if (isspace(*p)) 865 if (skip == TRUE) { 866 shift1left(p); 867 continue; 868 } else 869 break; 870 /* 871 * Only process the escape of the space seperator; 872 * since the token may contain other separators, 873 * let the other routines handle the escape of 874 * specific characters in the token. 875 */ 876 877 if (*p == '\\' && *(p + 1) != '\n' && isspace(*(p + 1))) { 878 shift1left(p); 879 } 880 p++; 881 } 882 if (*p == '\0') { 883 savep = 0; /* indicate this is last token */ 884 } else { 885 *p = '\0'; 886 savep = ++p; 887 } 888 trace1(TR_gettoken, 1); 889 return (strdup(retp)); 890 } 891 892 /* 893 * shift1left() moves all characters in the string over 1 to 894 * the left. 895 */ 896 897 static void 898 shift1left(p) 899 char *p; 900 { 901 trace1(TR_shift1left, 0); 902 for (; *p; p++) 903 *p = *(p + 1); 904 trace1(TR_shift1left, 1); 905 } 906 907 char * 908 nc_sperror() 909 { 910 static char buf_main[BUFSIZ]; 911 static pthread_key_t perror_key; 912 char *retstr = thr_main()? 913 buf_main : 914 thr_get_storage(&perror_key, BUFSIZ, free); 915 916 trace1(TR_nc_sperror, 0); 917 918 if (retstr == NULL) { 919 syslog(LOG_WARNING, 920 "nc_sperror: malloc failed when trying to create buffer\n"); 921 return (NULL); 922 } 923 924 switch (nc_error) { 925 case NC_NOERROR: 926 (void) strlcpy(retstr, dgettext(__nsl_dom, "no error"), BUFSIZ); 927 break; 928 case NC_NOMEM: 929 (void) strlcpy(retstr, dgettext(__nsl_dom, "out of memory"), 930 BUFSIZ); 931 break; 932 case NC_NOSET: 933 (void) strlcpy(retstr, dgettext(__nsl_dom, 934 "routine called before calling \ 935 setnetpath() or setnetconfig()"), BUFSIZ); 936 break; 937 case NC_OPENFAIL: 938 (void) strlcpy(retstr, 939 dgettext(__nsl_dom, "cannot open /etc/netconfig"), 940 BUFSIZ); 941 break; 942 case NC_BADLINE: 943 (void) snprintf(retstr, BUFSIZ, dgettext(__nsl_dom, 944 "error in /etc/netconfig: field %d of line %d\n"), 945 fieldnum, linenum); 946 break; 947 case NC_NOTFOUND: 948 (void) snprintf(retstr, BUFSIZ, 949 dgettext(__nsl_dom, 950 "netid not found in /etc/netconfig")); 951 break; 952 case NC_NOMOREENTRIES: 953 (void) snprintf(retstr, BUFSIZ, 954 dgettext(__nsl_dom, 955 "no more entries in /etc/netconfig")); 956 break; 957 default: 958 (void) strlcpy(retstr, dgettext(__nsl_dom, "unknown error"), 959 BUFSIZ); 960 break; 961 } 962 trace1(TR_nc_sperror, 1); 963 return (retstr); 964 } 965 966 void 967 nc_perror(const char *string) 968 { 969 trace1(TR_nc_perror, 0); 970 if (string) 971 fprintf(stderr, "%s: %s\n", string, nc_sperror()); 972 else 973 fprintf(stderr, "%s\n", nc_sperror()); 974 trace1(TR_nc_perror, 1); 975 } 976 977 static void 978 netlist_free(netppp) 979 struct netconfig ***netppp; 980 { 981 struct netconfig **tpp; 982 983 trace1(TR_netlist_free, 0); 984 for (tpp = *netppp; *tpp; tpp++) { 985 netconfig_free(*tpp); 986 } 987 free(*netppp); 988 *netppp = NULL; 989 trace1(TR_netlist_free, 1); 990 } 991 992 static void 993 netconfig_free(netconfigp) 994 struct netconfig *netconfigp; 995 { 996 int i; 997 998 trace1(TR_netconfig_free, 0); 999 if (netconfigp == NULL) { 1000 trace1(TR_netconfig_free, 1); 1001 return; 1002 } 1003 free_entry(netconfigp->nc_netid); 1004 free_entry(netconfigp->nc_protofmly); 1005 free_entry(netconfigp->nc_proto); 1006 free_entry(netconfigp->nc_device); 1007 if (netconfigp->nc_lookups) 1008 for (i = 0; i < netconfigp->nc_nlookups; i++) 1009 free_entry(netconfigp->nc_lookups[i]); 1010 free_entry(netconfigp->nc_lookups); 1011 free(netconfigp); 1012 trace1(TR_netconfig_free, 1); 1013 } 1014 1015 static struct netconfig * 1016 netconfig_dup(netconfigp) 1017 struct netconfig *netconfigp; 1018 { 1019 struct netconfig *nconf; 1020 int i; 1021 1022 trace1(TR_netconfig_dup, 0); 1023 nconf = (struct netconfig *)calloc(1, sizeof (struct netconfig)); 1024 if (nconf == NULL) { 1025 trace1(TR_netconfig_dup, 1); 1026 nc_error = NC_NOMEM; 1027 return (NULL); 1028 } 1029 nconf->nc_netid = strdup(netconfigp->nc_netid); 1030 nconf->nc_protofmly = strdup(netconfigp->nc_protofmly); 1031 nconf->nc_proto = strdup(netconfigp->nc_proto); 1032 nconf->nc_device = strdup(netconfigp->nc_device); 1033 nconf->nc_lookups = (char **)malloc((netconfigp->nc_nlookups + 1) 1034 * sizeof (char *)); 1035 if (!(nconf->nc_lookups && nconf->nc_netid && 1036 nconf->nc_protofmly && nconf->nc_proto && 1037 nconf->nc_device)) { 1038 nc_error = NC_NOMEM; 1039 netconfig_free(nconf); 1040 trace1(TR_netconfig_dup, 1); 1041 return (NULL); 1042 } 1043 1044 for (i = 0; i < netconfigp->nc_nlookups; i++) { 1045 nconf->nc_lookups[i] = strdup(netconfigp->nc_lookups[i]); 1046 if (nconf->nc_lookups[i] == NULL) { 1047 nconf->nc_nlookups = i; 1048 netconfig_free(nconf); 1049 nc_error = NC_NOMEM; 1050 trace1(TR_netconfig_dup, 1); 1051 return (NULL); 1052 } 1053 } 1054 nconf->nc_lookups[i] = NULL; 1055 nconf->nc_nlookups = netconfigp->nc_nlookups; 1056 nconf->nc_flag = netconfigp->nc_flag; 1057 nconf->nc_semantics = netconfigp->nc_semantics; 1058 trace1(TR_netconfig_dup, 1); 1059 return (nconf); 1060 } 1061 1062 static void 1063 free_entry(foo) 1064 void *foo; 1065 { 1066 trace1(TR_free_entry, 0); 1067 if (foo) 1068 free(foo); 1069 trace1(TR_free_entry, 1); 1070 } 1071