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