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