1 /* 2 * Copyright (c) 2009, Sun Microsystems, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * - Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * - Redistributions in binary form must reproduce the above copyright notice, 10 * this list of conditions and the following disclaimer in the documentation 11 * and/or other materials provided with the distribution. 12 * - Neither the name of Sun Microsystems, Inc. nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Copyright (c) 1989 by Sun Microsystems, Inc. 31 */ 32 33 #include <wintirpc.h> 34 //#include <pthread.h> 35 #include <reentrant.h> 36 //#include <sys/cdefs.h> 37 #include <stdio.h> 38 #include <errno.h> 39 #include <netconfig.h> 40 #include <stddef.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <rpc/rpc.h> 44 //#include <unistd.h> 45 #include "rpc_com.h" 46 47 #ifndef __REACTOS__ 48 // XXX FIXME - this is in wintirpc.c, but that is not currently built 49 static void wintirpc_debug(char *fmt, ...) 50 { 51 return; 52 } 53 #else 54 #define MSVCRT_CHECK_PMT(x) (x) 55 char * CDECL strtok_s(char *str, const char *delim, char **ctx) 56 { 57 if (!MSVCRT_CHECK_PMT(delim != NULL)) return NULL; 58 if (!MSVCRT_CHECK_PMT(ctx != NULL)) return NULL; 59 if (!MSVCRT_CHECK_PMT(str != NULL || *ctx != NULL)) return NULL; 60 61 if(!str) 62 str = *ctx; 63 64 while(*str && strchr(delim, *str)) 65 str++; 66 if(!*str) 67 { 68 *ctx = str; 69 return NULL; 70 } 71 72 *ctx = str+1; 73 while(**ctx && !strchr(delim, **ctx)) 74 (*ctx)++; 75 if(**ctx) 76 *(*ctx)++ = 0; 77 78 return str; 79 } 80 #endif 81 82 /* 83 * The five library routines in this file provide application access to the 84 * system network configuration database, /etc/netconfig. In addition to the 85 * netconfig database and the routines for accessing it, the environment 86 * variable NETPATH and its corresponding routines in getnetpath.c may also be 87 * used to specify the network transport to be used. 88 */ 89 90 /* 91 * netconfig errors 92 */ 93 94 #define NC_NONETCONFIG ENOENT 95 #define NC_NOMEM ENOMEM 96 #define NC_NOTINIT EINVAL /* setnetconfig was not called first */ 97 #define NC_BADFILE EBADF /* format for netconfig file is bad */ 98 #define NC_NOTFOUND WSAENOPROTOOPT /* specified netid was not found */ 99 100 /* 101 * semantics as strings (should be in netconfig.h) 102 */ 103 #define NC_TPI_CLTS_S "tpi_clts" 104 #define NC_TPI_COTS_S "tpi_cots" 105 #define NC_TPI_COTS_ORD_S "tpi_cots_ord" 106 #define NC_TPI_RAW_S "tpi_raw" 107 108 /* 109 * flags as characters (also should be in netconfig.h) 110 */ 111 #define NC_NOFLAG_C '-' 112 #define NC_VISIBLE_C 'v' 113 #define NC_BROADCAST_C 'b' 114 115 /* 116 * Character used to indicate there is no name-to-address lookup library 117 */ 118 #define NC_NOLOOKUP "-" 119 120 static const char * const _nc_errors[] = { 121 "Netconfig database not found", 122 "Not enough memory", 123 "Not initialized", 124 "Netconfig database has invalid format", 125 "Netid not found in netconfig database" 126 }; 127 128 struct netconfig_info { 129 int eof; /* all entries has been read */ 130 int ref; /* # of times setnetconfig() has been called */ 131 struct netconfig_list *head; /* head of the list */ 132 struct netconfig_list *tail; /* last of the list */ 133 }; 134 135 struct netconfig_list { 136 char *linep; /* hold line read from netconfig */ 137 struct netconfig *ncp; 138 struct netconfig_list *next; 139 }; 140 141 struct netconfig_vars { 142 int valid; /* token that indicates a valid netconfig_vars */ 143 int flag; /* first time flag */ 144 struct netconfig_list *nc_configs; /* pointer to the current netconfig entry */ 145 }; 146 147 #define NC_VALID 0xfeed 148 #define NC_STORAGE 0xf00d 149 #define NC_INVALID 0 150 151 152 static int *__nc_error(void); 153 static int parse_ncp(char *, struct netconfig *); 154 static struct netconfig *dup_ncp(struct netconfig *); 155 156 157 static FILE *nc_file; /* for netconfig db */ 158 static struct netconfig_info ni = { 0, 0, NULL, NULL}; 159 160 #define MAXNETCONFIGLINE 1000 161 162 static int * 163 __nc_error() 164 { 165 extern mutex_t nc_lock; 166 extern thread_key_t nc_key; 167 static int nc_error = 0; 168 int error, *nc_addr; 169 170 /* 171 * Use the static `nc_error' if we are the main thread 172 * (including non-threaded programs), or if an allocation 173 * fails. 174 */ 175 if (nc_key == -1) { 176 error = 0; 177 mutex_lock(&nc_lock); 178 if (nc_key == -1) 179 error = nc_key = TlsAlloc(); //thr_keycreate(&nc_key, free); 180 mutex_unlock(&nc_lock); 181 if (error == TLS_OUT_OF_INDEXES) 182 return (&nc_error); 183 } 184 if ((nc_addr = (int *)thr_getspecific(nc_key)) == NULL) { 185 nc_addr = (int *)malloc(sizeof (int *)); 186 if (thr_setspecific(nc_key, (void *) nc_addr) == 0) { 187 if (nc_addr) 188 free(nc_addr); 189 return (&nc_error); 190 } 191 *nc_addr = 0; 192 } 193 return (nc_addr); 194 } 195 196 #define nc_error (*(__nc_error())) 197 /* 198 * A call to setnetconfig() establishes a /etc/netconfig "session". A session 199 * "handle" is returned on a successful call. At the start of a session (after 200 * a call to setnetconfig()) searches through the /etc/netconfig database will 201 * proceed from the start of the file. The session handle must be passed to 202 * getnetconfig() to parse the file. Each call to getnetconfig() using the 203 * current handle will process one subsequent entry in /etc/netconfig. 204 * setnetconfig() must be called before the first call to getnetconfig(). 205 * (Handles are used to allow for nested calls to setnetpath()). 206 * 207 * A new session is established with each call to setnetconfig(), with a new 208 * handle being returned on each call. Previously established sessions remain 209 * active until endnetconfig() is called with that session's handle as an 210 * argument. 211 * 212 * setnetconfig() need *not* be called before a call to getnetconfigent(). 213 * setnetconfig() returns a NULL pointer on failure (for example, if 214 * the netconfig database is not present). 215 */ 216 void * 217 setnetconfig() 218 { 219 struct netconfig_vars *nc_vars; 220 221 if ((nc_vars = (struct netconfig_vars *)malloc(sizeof 222 (struct netconfig_vars))) == NULL) { 223 return(NULL); 224 } 225 226 /* 227 * For multiple calls, i.e. nc_file is not NULL, we just return the 228 * handle without reopening the netconfig db. 229 */ 230 ni.ref++; 231 if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "r")) != NULL) { 232 nc_vars->valid = NC_VALID; 233 nc_vars->flag = 0; 234 nc_vars->nc_configs = ni.head; 235 return ((void *)nc_vars); 236 } 237 ni.ref--; 238 nc_error = NC_NONETCONFIG; 239 free(nc_vars); 240 return (NULL); 241 } 242 243 244 /* 245 * When first called, getnetconfig() returns a pointer to the first entry in 246 * the netconfig database, formatted as a struct netconfig. On each subsequent 247 * call, getnetconfig() returns a pointer to the next entry in the database. 248 * getnetconfig() can thus be used to search the entire netconfig file. 249 * getnetconfig() returns NULL at end of file. 250 */ 251 252 struct netconfig * 253 getnetconfig(handlep) 254 void *handlep; 255 { 256 struct netconfig_vars *ncp = (struct netconfig_vars *)handlep; 257 char *stringp; /* tmp string pointer */ 258 struct netconfig_list *list; 259 struct netconfig *np; 260 261 /* 262 * Verify that handle is valid 263 */ 264 if (ncp == NULL || nc_file == NULL) { 265 nc_error = NC_NOTINIT; 266 return (NULL); 267 } 268 269 switch (ncp->valid) { 270 case NC_VALID: 271 /* 272 * If entry has already been read into the list, 273 * we return the entry in the linked list. 274 * If this is the first time call, check if there are any entries in 275 * linked list. If no entries, we need to read the netconfig db. 276 * If we have been here and the next entry is there, we just return 277 * it. 278 */ 279 if (ncp->flag == 0) { /* first time */ 280 ncp->flag = 1; 281 ncp->nc_configs = ni.head; 282 if (ncp->nc_configs != NULL) /* entry already exist */ 283 return(ncp->nc_configs->ncp); 284 } 285 else if (ncp->nc_configs != NULL && ncp->nc_configs->next != NULL) { 286 ncp->nc_configs = ncp->nc_configs->next; 287 return(ncp->nc_configs->ncp); 288 } 289 290 /* 291 * If we cannot find the entry in the list and is end of file, 292 * we give up. 293 */ 294 if (ni.eof == 1) 295 return(NULL); 296 break; 297 default: 298 nc_error = NC_NOTINIT; 299 return (NULL); 300 } 301 302 stringp = (char *) malloc(MAXNETCONFIGLINE); 303 if (stringp == NULL) 304 return (NULL); 305 306 #ifdef MEM_CHK 307 if (malloc_verify() == 0) { 308 fprintf(stderr, "memory heap corrupted in getnetconfig\n"); 309 exit(1); 310 } 311 #endif 312 313 /* 314 * Read a line from netconfig file. 315 */ 316 do { 317 if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) { 318 free(stringp); 319 ni.eof = 1; 320 return (NULL); 321 } 322 } while (*stringp == '#'); 323 324 list = (struct netconfig_list *) malloc(sizeof (struct netconfig_list)); 325 if (list == NULL) { 326 free(stringp); 327 return(NULL); 328 } 329 np = (struct netconfig *) malloc(sizeof (struct netconfig)); 330 if (np == NULL) { 331 free(stringp); 332 free(list); 333 return(NULL); 334 } 335 list->ncp = np; 336 list->next = NULL; 337 list->ncp->nc_lookups = NULL; 338 list->linep = stringp; 339 wintirpc_debug("%s: before parse: &list->linep %p, list->linep %p, stringp %p\n", __FUNCTION__, &list->linep, list->linep, stringp); 340 if (parse_ncp(stringp, list->ncp) == -1) { 341 free(stringp); 342 free(np); 343 free(list); 344 return (NULL); 345 } else { 346 wintirpc_debug("%s: after parse: list->linep %p, stringp %p\n", __FUNCTION__, list->linep, stringp); 347 /* 348 * If this is the first entry that's been read, it is the head of 349 * the list. If not, put the entry at the end of the list. 350 * Reposition the current pointer of the handle to the last entry 351 * in the list. 352 */ 353 if (ni.head == NULL) { /* first entry */ 354 ni.head = ni.tail = list; 355 } 356 else { 357 ni.tail->next = list; 358 ni.tail = ni.tail->next; 359 } 360 ncp->nc_configs = ni.tail; 361 return(ni.tail->ncp); 362 } 363 } 364 365 /* 366 * endnetconfig() may be called to "unbind" or "close" the netconfig database 367 * when processing is complete, releasing resources for reuse. endnetconfig() 368 * may not be called before setnetconfig(). endnetconfig() returns 0 on 369 * success and -1 on failure (for example, if setnetconfig() was not called 370 * previously). 371 */ 372 int 373 endnetconfig(handlep) 374 void *handlep; 375 { 376 struct netconfig_vars *nc_handlep = (struct netconfig_vars *)handlep; 377 378 struct netconfig_list *q, *p; 379 380 /* 381 * Verify that handle is valid 382 */ 383 if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID && 384 nc_handlep->valid != NC_STORAGE)) { 385 nc_error = NC_NOTINIT; 386 return (-1); 387 } 388 389 /* 390 * Return 0 if anyone still needs it. 391 */ 392 nc_handlep->valid = NC_INVALID; 393 nc_handlep->flag = 0; 394 nc_handlep->nc_configs = NULL; 395 if (--ni.ref > 0) { 396 free(nc_handlep); 397 return(0); 398 } 399 400 /* 401 * Noone needs these entries anymore, then frees them. 402 * Make sure all info in netconfig_info structure has been reinitialized. 403 */ 404 q = p = ni.head; 405 ni.eof = ni.ref = 0; 406 ni.head = NULL; 407 ni.tail = NULL; 408 while (q) { 409 p = q->next; 410 if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups); 411 free(q->ncp); 412 free(q->linep); 413 free(q); 414 q = p; 415 } 416 free(nc_handlep); 417 418 fclose(nc_file); 419 nc_file = NULL; 420 return (0); 421 } 422 423 /* 424 * getnetconfigent(netid) returns a pointer to the struct netconfig structure 425 * corresponding to netid. It returns NULL if netid is invalid (that is, does 426 * not name an entry in the netconfig database). It returns NULL and sets 427 * errno in case of failure (for example, if the netconfig database cannot be 428 * opened). 429 */ 430 431 struct netconfig * 432 getnetconfigent(netid) 433 const char *netid; 434 { 435 FILE *file; /* NETCONFIG db's file pointer */ 436 char *linep; /* holds current netconfig line */ 437 char *stringp; /* temporary string pointer */ 438 struct netconfig *ncp = NULL; /* returned value */ 439 struct netconfig_list *list; /* pointer to cache list */ 440 441 nc_error = NC_NOTFOUND; /* default error. */ 442 if (netid == NULL || strlen(netid) == 0) { 443 return (NULL); 444 } 445 446 if (strcmp(netid, "unix") == 0) { 447 fprintf(stderr, "The local transport is called \"unix\" "); 448 fprintf(stderr, "in /etc/netconfig.\n"); 449 fprintf(stderr, "Please change this to \"local\" manually "); 450 fprintf(stderr, "or run mergemaster(8).\n"); 451 fprintf(stderr, "See UPDATING entry 20021216 for details.\n"); 452 fprintf(stderr, "Continuing in 10 seconds\n\n"); 453 fprintf(stderr, "This warning will be removed 20030301\n"); 454 Sleep(10000); // sleep(10); 455 } 456 457 /* 458 * Look up table if the entries have already been read and parsed in 459 * getnetconfig(), then copy this entry into a buffer and return it. 460 * If we cannot find the entry in the current list and there are more 461 * entries in the netconfig db that has not been read, we then read the 462 * db and try find the match netid. 463 * If all the netconfig db has been read and placed into the list and 464 * there is no match for the netid, return NULL. 465 */ 466 if (ni.head != NULL) { 467 for (list = ni.head; list; list = list->next) { 468 if (strcmp(list->ncp->nc_netid, netid) == 0) { 469 return(dup_ncp(list->ncp)); 470 } 471 } 472 if (ni.eof == 1) /* that's all the entries */ 473 return(NULL); 474 } 475 476 477 if ((file = fopen(NETCONFIG, "r")) == NULL) { 478 nc_error = NC_NONETCONFIG; 479 return (NULL); 480 } 481 482 if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) { 483 fclose(file); 484 nc_error = NC_NOMEM; 485 return (NULL); 486 } 487 do { 488 ptrdiff_t len; 489 char *tmpp; /* tmp string pointer */ 490 491 do { 492 if ((stringp = fgets(linep, MAXNETCONFIGLINE, file)) == NULL) { 493 break; 494 } 495 } while (*stringp == '#'); 496 if (stringp == NULL) { /* eof */ 497 break; 498 } 499 if ((tmpp = strpbrk(stringp, "\t ")) == NULL) { /* can't parse file */ 500 nc_error = NC_BADFILE; 501 break; 502 } 503 if (strlen(netid) == (size_t) (len = tmpp - stringp) && /* a match */ 504 strncmp(stringp, netid, (size_t)len) == 0) { 505 if ((ncp = (struct netconfig *) 506 malloc(sizeof (struct netconfig))) == NULL) { 507 break; 508 } 509 ncp->nc_lookups = NULL; 510 if (parse_ncp(linep, ncp) == -1) { 511 free(ncp); 512 ncp = NULL; 513 } 514 break; 515 } 516 } while (stringp != NULL); 517 if (ncp == NULL) { 518 free(linep); 519 } 520 fclose(file); 521 return(ncp); 522 } 523 524 /* 525 * freenetconfigent(netconfigp) frees the netconfig structure pointed to by 526 * netconfigp (previously returned by getnetconfigent()). 527 */ 528 529 void 530 freenetconfigent(netconfigp) 531 struct netconfig *netconfigp; 532 { 533 if (netconfigp != NULL) { 534 free(netconfigp->nc_netid); /* holds all netconfigp's strings */ 535 if (netconfigp->nc_lookups != NULL) 536 free(netconfigp->nc_lookups); 537 free(netconfigp); 538 } 539 return; 540 } 541 542 /* 543 * Parse line and stuff it in a struct netconfig 544 * Typical line might look like: 545 * udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so 546 * 547 * We return -1 if any of the tokens don't parse, or malloc fails. 548 * 549 * Note that we modify stringp (putting NULLs after tokens) and 550 * we set the ncp's string field pointers to point to these tokens within 551 * stringp. 552 */ 553 554 static int 555 parse_ncp(stringp, ncp) 556 char *stringp; /* string to parse */ 557 struct netconfig *ncp; /* where to put results */ 558 { 559 char *tokenp; /* for processing tokens */ 560 char *lasts; 561 562 nc_error = NC_BADFILE; /* nearly anything that breaks is for this reason */ 563 wintirpc_debug("%s: The last character being chopped is '%02x'\n", __FUNCTION__, stringp[strlen(stringp)-1]); 564 wintirpc_debug("%s: The string before chopping is '%s'\n", __FUNCTION__, stringp); 565 stringp[strlen(stringp)-1] = '\0'; /* get rid of newline */ 566 wintirpc_debug("%s: The last character after chopping is '%02x'\n", __FUNCTION__, stringp[strlen(stringp)-1]); 567 wintirpc_debug("%s: The string after chopping is '%s'\n", __FUNCTION__, stringp); 568 /* netid */ 569 if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL) { 570 return (-1); 571 } 572 573 /* semantics */ 574 if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { 575 return (-1); 576 } 577 if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0) 578 ncp->nc_semantics = NC_TPI_COTS_ORD; 579 else if (strcmp(tokenp, NC_TPI_COTS_S) == 0) 580 ncp->nc_semantics = NC_TPI_COTS; 581 else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0) 582 ncp->nc_semantics = NC_TPI_CLTS; 583 else if (strcmp(tokenp, NC_TPI_RAW_S) == 0) 584 ncp->nc_semantics = NC_TPI_RAW; 585 else 586 return (-1); 587 588 /* flags */ 589 if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { 590 return (-1); 591 } 592 for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0'; 593 tokenp++) { 594 switch (*tokenp) { 595 case NC_NOFLAG_C: 596 break; 597 case NC_VISIBLE_C: 598 ncp->nc_flag |= NC_VISIBLE; 599 break; 600 case NC_BROADCAST_C: 601 ncp->nc_flag |= NC_BROADCAST; 602 break; 603 default: 604 return (-1); 605 } 606 } 607 /* protocol family */ 608 if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL) { 609 return (-1); 610 } 611 /* protocol name */ 612 if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL) { 613 return (-1); 614 } 615 /* network device */ 616 if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL) { 617 return (-1); 618 } 619 if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { 620 return (-1); 621 } 622 if (strcmp(tokenp, NC_NOLOOKUP) == 0) { 623 ncp->nc_nlookups = 0; 624 ncp->nc_lookups = NULL; 625 } else { 626 char *cp; /* tmp string */ 627 628 if (ncp->nc_lookups != NULL) /* from last visit */ 629 free(ncp->nc_lookups); 630 /* preallocate one string pointer */ 631 ncp->nc_lookups = (char **)malloc(sizeof (char *)); 632 ncp->nc_nlookups = 0; 633 while ((cp = tokenp) != NULL) { 634 tokenp = _get_next_token(cp, ','); 635 ncp->nc_lookups[(size_t)ncp->nc_nlookups++] = cp; 636 ncp->nc_lookups = (char **)realloc(ncp->nc_lookups, 637 (size_t)(ncp->nc_nlookups+1) *sizeof(char *)); /* for next loop */ 638 } 639 } 640 return (0); 641 } 642 643 644 /* 645 * Returns a string describing the reason for failure. 646 */ 647 char * 648 nc_sperror() 649 { 650 const char *message; 651 652 switch(nc_error) { 653 case NC_NONETCONFIG: 654 message = _nc_errors[0]; 655 break; 656 case NC_NOMEM: 657 message = _nc_errors[1]; 658 break; 659 case NC_NOTINIT: 660 message = _nc_errors[2]; 661 break; 662 case NC_BADFILE: 663 message = _nc_errors[3]; 664 break; 665 case NC_NOTFOUND: 666 message = _nc_errors[4]; 667 break; 668 default: 669 message = "Unknown network selection error"; 670 } 671 /* LINTED const castaway */ 672 return ((char *)message); 673 } 674 675 /* 676 * Prints a message onto standard error describing the reason for failure. 677 */ 678 void 679 nc_perror(s) 680 const char *s; 681 { 682 fprintf(stderr, "%s: %s\n", s, nc_sperror()); 683 } 684 685 /* 686 * Duplicates the matched netconfig buffer. 687 */ 688 static struct netconfig * 689 dup_ncp(ncp) 690 struct netconfig *ncp; 691 { 692 struct netconfig *p; 693 char *tmp; 694 u_int i; 695 696 if ((tmp=malloc(MAXNETCONFIGLINE)) == NULL) 697 return(NULL); 698 if ((p=(struct netconfig *)malloc(sizeof(struct netconfig))) == NULL) { 699 free(tmp); 700 return(NULL); 701 } 702 /* 703 * First we dup all the data from matched netconfig buffer. Then we 704 * adjust some of the member pointer to a pre-allocated buffer where 705 * contains part of the data. 706 * To follow the convention used in parse_ncp(), we store all the 707 * necessary information in the pre-allocated buffer and let each 708 * of the netconfig char pointer member point to the right address 709 * in the buffer. 710 */ 711 *p = *ncp; 712 p->nc_netid = (char *)strcpy(tmp,ncp->nc_netid); 713 tmp = strchr(tmp, 0) + 1; 714 p->nc_protofmly = (char *)strcpy(tmp,ncp->nc_protofmly); 715 tmp = strchr(tmp, 0) + 1; 716 p->nc_proto = (char *)strcpy(tmp,ncp->nc_proto); 717 tmp = strchr(tmp, 0) + 1; 718 p->nc_device = (char *)strcpy(tmp,ncp->nc_device); 719 p->nc_lookups = (char **)malloc((size_t)(p->nc_nlookups+1) * sizeof(char *)); 720 if (p->nc_lookups == NULL) { 721 free(p->nc_netid); 722 return(NULL); 723 } 724 for (i=0; i < p->nc_nlookups; i++) { 725 tmp = strchr(tmp, 0) + 1; 726 p->nc_lookups[i] = (char *)strcpy(tmp,ncp->nc_lookups[i]); 727 } 728 return(p); 729 } 730