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 *
__nc_error(void)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 *
setnetconfig(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
endnetconfig(void * vdata)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 *
getnetconfig(void * vdata)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 *
getnetconfigent(const char * netid)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
freenetconfigent(struct netconfig * netp)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 **
getnetlist(void)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 *
fgetnetconfig(FILE * fp,char * netid)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 *
setnetpath(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
endnetpath(void * vdata)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 *
getnetpath(void * vdata)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
blank(char * cp)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
comment(char * cp)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
getvalue(char * cp,struct nc_data nc_data[])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
getflag(char * cp)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 **
getlookups(char * cp)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
getnlookups(char * cp)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 *
gettoken(char * cp,int skip)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
shift1left(char * p)808 shift1left(char *p)
809 {
810 for (; *p; p++)
811 *p = *(p + 1);
812 }
813
814 char *
nc_sperror(void)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
nc_perror(const char * string)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
netlist_free(struct netconfig *** netppp)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
netconfig_free(struct netconfig * netconfigp)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 *
netconfig_dup(struct netconfig * netconfigp)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
free_entry(void * foo)951 free_entry(void *foo)
952 {
953 if (foo)
954 free(foo);
955 }
956