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